<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Google Colab | Lenka&#39;s blog</title>
    <link>https://lenkastatham.com/categories/google-colab.html</link>
      <atom:link href="https://lenkastatham.com/categories/google-colab/index.xml" rel="self" type="application/rss+xml" />
    <description>Google Colab</description>
    <generator>Source Themes Academic (https://sourcethemes.com/academic/)</generator><language>en-gb</language><lastBuildDate>Fri, 12 Mar 2021 00:00:00 +0000</lastBuildDate>
    <image>
      <url>https://lenkastatham.com/img/icon-192.png</url>
      <title>Google Colab</title>
      <link>https://lenkastatham.com/categories/google-colab.html</link>
    </image>
    
    <item>
      <title>Calculating Walking distance in Python. Networkx vs Pandana.</title>
      <link>https://lenkastatham.com/post/pandana.html</link>
      <pubDate>Fri, 12 Mar 2021 00:00:00 +0000</pubDate>
      <guid>https://lenkastatham.com/post/pandana.html</guid>
      <description>&lt;h2 id=&#34;introduction&#34;&gt;Introduction&lt;/h2&gt;
&lt;p&gt;Let&#39;s say you have spatial point data and you want to calculate walking distances between all combination of the points. For example, you have data of local bars and you want to find out all the walking distances between them, so you can include them in your regression model (or anything else), for example as a variable that defines how accessible two pubs are to each other.&lt;/p&gt;
&lt;p&gt;This post will show you how you can do that in python using&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;em&gt;&lt;a href=&#34;https://osmnx.readthedocs.io/en/stable/&#34;&gt;osmnx&lt;/a&gt;&lt;/em&gt; package to generate OSM road network&lt;/li&gt;
&lt;li&gt;&lt;em&gt;&lt;a href=&#34;https://networkx.org/documentation/stable/tutorial.html&#34;&gt;networkx&lt;/a&gt;&lt;/em&gt; package to find the nearest point on that network and calulate the walking distance between them&lt;/li&gt;
&lt;li&gt;&lt;em&gt;&lt;a href=&#34;http://udst.github.io/pandana/&#34;&gt;pandana&lt;/a&gt;&lt;/em&gt; package to make this significantly faster!&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;data&#34;&gt;Data&lt;/h2&gt;
&lt;p&gt;Availiable &lt;a href=&#34;https://github.com/lenkahas/sample_data/blob/main/points.geojson&#34;&gt;here&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&#34;background&#34;&gt;Background&lt;/h2&gt;
&lt;p&gt;You might need some essential information that will help you to understand what we are doing here. Feel free to skip this part and go straight to the code.&lt;/p&gt;
&lt;h3 id=&#34;what-is-the-walking-distance&#34;&gt;What is the walking distance?&lt;/h3&gt;
&lt;p&gt;It&#39;s exactly what it says. Walking distance from one place to another. In other words, how far is the place from where I stand along the walking path. This information is crucial for estimating how long is it going to take me to go there, how much effort or money will this cost me. Those are all variables that contribute to estimations of accessibility, connectivity, mobility or others.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;./pandana/Graphs2.png&#34; alt=&#34;graph2&#34;&gt;&lt;/p&gt;
&lt;h3 id=&#34;estimating-the-walking-distance&#34;&gt;Estimating the walking distance.&lt;/h3&gt;
&lt;p&gt;The distance between two places/nodes is then the sum of the weights/lengths of all the paths/roads/edges that connects them.&lt;/p&gt;
&lt;p&gt;This can be also referred to as the &lt;a href=&#34;https://en.wikipedia.org/wiki/Shortest_path_problem&#34;&gt;Shortest Path Problem&lt;/a&gt;, in which we are looking for the most efficient paths between nodes.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;./pandana/Graph.png&#34; alt=&#34;graph&#34;&gt;&lt;/p&gt;
&lt;p&gt;In this example, the shortest path between Node 1 and Node 2 is the $$SUM(Weight 3, Weight 2, Weight 4)$$.
So if the weights represent a number of minutes (how long it takes to walk that path) then we would walk for 7 minutes.
$$ 1+2+4=7$$&lt;/p&gt;
&lt;p&gt;If would choose to go the other way, which is seemingly shorter,
$$SUM(Weight 1, Weight 4)$$
$$8+4=12$$
We would walk for 12 minutes. Therefore the first option is the most efficient one.&lt;/p&gt;
&lt;h3 id=&#34;find-the-nearest-neighbour&#34;&gt;Find the Nearest Neighbour&lt;/h3&gt;
&lt;p&gt;In any scenarios where the places you want to use for your analysis are not directly placed on the road or path, we need to connect the place to the network. We do this by finding the &lt;em&gt;Nearest neighbouring&lt;/em&gt; node on the graph/network to the specific place.
Both packages (networkx and pandana) have their own functions that can be used for these purposes.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;./pandana/Graphs3.png&#34; alt=&#34;graph&#34;&gt;&lt;/p&gt;
&lt;h2 id=&#34;load-the-packages&#34;&gt;Load the packages&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;import pandas as pd
import numpy as np
import geopandas as gpd
import matplotlib.pyplot as plt
import osmnx as ox # install osmnx first, it will download appropriate version of networkx
import networkx as nx
from pyproj import CRS
import itertools

import pandana
print(pandana.__version__)
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;# define coordinates if you need them
wgs84 = CRS(4326)
bng = CRS(27700)
print(wgs84)
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;epsg:4326
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&#34;load-the-point-data-and-create-flows&#34;&gt;Load the point data and create flows&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;pois = gpd.read_file(&amp;quot;./points.geojson&amp;quot;)
#pois.crs # check the CRS
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;pois.head()
&lt;/code&gt;&lt;/pre&gt;
&lt;div&gt;
&lt;style scoped&gt;
    .dataframe tbody tr th:only-of-type {
        vertical-align: middle;
    }
&lt;pre&gt;&lt;code&gt;.dataframe tbody tr th {
    vertical-align: top;
}

.dataframe thead th {
    text-align: right;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;/style&gt;&lt;/p&gt;
&lt;table border=&#34;1&#34; class=&#34;dataframe&#34;&gt;
  &lt;thead&gt;
    &lt;tr style=&#34;text-align: right;&#34;&gt;
      &lt;th&gt;&lt;/th&gt;
      &lt;th&gt;ID_code&lt;/th&gt;
      &lt;th&gt;X&lt;/th&gt;
      &lt;th&gt;Y&lt;/th&gt;
      &lt;th&gt;geometry&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;th&gt;0&lt;/th&gt;
      &lt;td&gt;A91120&lt;/td&gt;
      &lt;td&gt;-2.559063&lt;/td&gt;
      &lt;td&gt;51.502830&lt;/td&gt;
      &lt;td&gt;POINT (-2.55906 51.50283)&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th&gt;1&lt;/th&gt;
      &lt;td&gt;A99931&lt;/td&gt;
      &lt;td&gt;-2.596140&lt;/td&gt;
      &lt;td&gt;51.459182&lt;/td&gt;
      &lt;td&gt;POINT (-2.59614 51.45918)&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th&gt;2&lt;/th&gt;
      &lt;td&gt;A99986&lt;/td&gt;
      &lt;td&gt;-2.538833&lt;/td&gt;
      &lt;td&gt;51.483143&lt;/td&gt;
      &lt;td&gt;POINT (-2.53883 51.48314)&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th&gt;3&lt;/th&gt;
      &lt;td&gt;L81002&lt;/td&gt;
      &lt;td&gt;-2.930352&lt;/td&gt;
      &lt;td&gt;51.360207&lt;/td&gt;
      &lt;td&gt;POINT (-2.93035 51.36021)&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th&gt;4&lt;/th&gt;
      &lt;td&gt;L81004&lt;/td&gt;
      &lt;td&gt;-2.767317&lt;/td&gt;
      &lt;td&gt;51.482805&lt;/td&gt;
      &lt;td&gt;POINT (-2.76732 51.48281)&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;# tale first 5 points and find all possinle combinations
pois = pois.iloc[0:6,:]

# create a list of all the ID&#39;s
p_li = list(pois[&#39;ID_code&#39;].unique())

# get all unique combinations of all the origins and destinations
flows = pd.DataFrame(list(itertools.product(p_li,p_li))).rename(columns = {0:&#39;origin&#39;,1:&#39;destination&#39;})

flows.info()
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;class &#39;pandas.core.frame.DataFrame&#39;&amp;gt;
RangeIndex: 36 entries, 0 to 35
Data columns (total 2 columns):
 #   Column       Non-Null Count  Dtype 
---  ------       --------------  ----- 
 0   origin       36 non-null     object
 1   destination  36 non-null     object
dtypes: object(2)
memory usage: 704.0+ bytes
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&#34;using-networkx&#34;&gt;Using Networkx&lt;/h2&gt;
&lt;h3 id=&#34;load-graph&#34;&gt;Load Graph&lt;/h3&gt;
&lt;p&gt;The osmnx package has very useful function &amp;lsquo;graph_from_bbox&amp;rsquo; which loads the osm roads graph quite quickly. Here I am loading walking paths for whola area of Avon where my points are located, which is quite a big area so expect this to take few minutes.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;# create bounding box for our data 
bbox = [51.623985, 51.291124,  -2.272797, -3.029480] 

# generate graph based on the bounding box
avon = ox.graph_from_bbox(bbox[0], bbox[1], bbox[2], bbox[3], 
                               retain_all=False, 
                               truncate_by_edge=True, 
                               simplify=False,
                               network_type=&#39;walk&#39;)
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;# get the nodes and the edges into geopandas
nodes, edges = ox.graph_to_gdfs(avon, nodes=True, edges=True)
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&#34;find-the-nearest-node-to-each-point-with-osmnxget-nearest-node&#34;&gt;Find the nearest node to each point with osmnx.get_nearest_node()&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;# define function for the nearest neighbour
def nearest_node(a,b):
    nearest_node,dist=ox.get_nearest_node(avon, (a,b), return_dist=True, method = &#39;euclidean&#39;)  
    return nearest_node
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;# apply the function
pois[&#39;NX_node&#39;] = np.vectorize(nearest_node)(pois[&#39;Y&#39;],pois[&#39;X&#39;])
pois.head()
&lt;/code&gt;&lt;/pre&gt;
&lt;div&gt;
&lt;style scoped&gt;
    .dataframe tbody tr th:only-of-type {
        vertical-align: middle;
    }
&lt;pre&gt;&lt;code&gt;.dataframe tbody tr th {
    vertical-align: top;
}

.dataframe thead th {
    text-align: right;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;/style&gt;&lt;/p&gt;
&lt;table border=&#34;1&#34; class=&#34;dataframe&#34;&gt;
  &lt;thead&gt;
    &lt;tr style=&#34;text-align: right;&#34;&gt;
      &lt;th&gt;&lt;/th&gt;
      &lt;th&gt;ID_code&lt;/th&gt;
      &lt;th&gt;X&lt;/th&gt;
      &lt;th&gt;Y&lt;/th&gt;
      &lt;th&gt;geometry&lt;/th&gt;
      &lt;th&gt;NX_node&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;th&gt;0&lt;/th&gt;
      &lt;td&gt;A91120&lt;/td&gt;
      &lt;td&gt;-2.559063&lt;/td&gt;
      &lt;td&gt;51.502830&lt;/td&gt;
      &lt;td&gt;POINT (-2.55906 51.50283)&lt;/td&gt;
      &lt;td&gt;2914306154&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th&gt;1&lt;/th&gt;
      &lt;td&gt;A99931&lt;/td&gt;
      &lt;td&gt;-2.596140&lt;/td&gt;
      &lt;td&gt;51.459182&lt;/td&gt;
      &lt;td&gt;POINT (-2.59614 51.45918)&lt;/td&gt;
      &lt;td&gt;1859320333&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th&gt;2&lt;/th&gt;
      &lt;td&gt;A99986&lt;/td&gt;
      &lt;td&gt;-2.538833&lt;/td&gt;
      &lt;td&gt;51.483143&lt;/td&gt;
      &lt;td&gt;POINT (-2.53883 51.48314)&lt;/td&gt;
      &lt;td&gt;2094196650&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th&gt;3&lt;/th&gt;
      &lt;td&gt;L81002&lt;/td&gt;
      &lt;td&gt;-2.930352&lt;/td&gt;
      &lt;td&gt;51.360207&lt;/td&gt;
      &lt;td&gt;POINT (-2.93035 51.36021)&lt;/td&gt;
      &lt;td&gt;317399984&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th&gt;4&lt;/th&gt;
      &lt;td&gt;L81004&lt;/td&gt;
      &lt;td&gt;-2.767317&lt;/td&gt;
      &lt;td&gt;51.482805&lt;/td&gt;
      &lt;td&gt;POINT (-2.76732 51.48281)&lt;/td&gt;
      &lt;td&gt;2488740793&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;# create list of the node id&#39;s and check if they exist and if they are on the right place
nodelist = list(pois[&#39;NX_node&#39;].unique())

nodes[nodes.index.isin(nodelist)]
&lt;/code&gt;&lt;/pre&gt;
&lt;div&gt;
&lt;style scoped&gt;
    .dataframe tbody tr th:only-of-type {
        vertical-align: middle;
    }
&lt;pre&gt;&lt;code&gt;.dataframe tbody tr th {
    vertical-align: top;
}

.dataframe thead th {
    text-align: right;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;/style&gt;&lt;/p&gt;
&lt;table border=&#34;1&#34; class=&#34;dataframe&#34;&gt;
  &lt;thead&gt;
    &lt;tr style=&#34;text-align: right;&#34;&gt;
      &lt;th&gt;&lt;/th&gt;
      &lt;th&gt;y&lt;/th&gt;
      &lt;th&gt;x&lt;/th&gt;
      &lt;th&gt;street_count&lt;/th&gt;
      &lt;th&gt;highway&lt;/th&gt;
      &lt;th&gt;ref&lt;/th&gt;
      &lt;th&gt;geometry&lt;/th&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th&gt;osmid&lt;/th&gt;
      &lt;th&gt;&lt;/th&gt;
      &lt;th&gt;&lt;/th&gt;
      &lt;th&gt;&lt;/th&gt;
      &lt;th&gt;&lt;/th&gt;
      &lt;th&gt;&lt;/th&gt;
      &lt;th&gt;&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;th&gt;317399984&lt;/th&gt;
      &lt;td&gt;51.360246&lt;/td&gt;
      &lt;td&gt;-2.930589&lt;/td&gt;
      &lt;td&gt;2&lt;/td&gt;
      &lt;td&gt;NaN&lt;/td&gt;
      &lt;td&gt;NaN&lt;/td&gt;
      &lt;td&gt;POINT (-2.93059 51.36025)&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th&gt;1859320333&lt;/th&gt;
      &lt;td&gt;51.459442&lt;/td&gt;
      &lt;td&gt;-2.596420&lt;/td&gt;
      &lt;td&gt;2&lt;/td&gt;
      &lt;td&gt;NaN&lt;/td&gt;
      &lt;td&gt;NaN&lt;/td&gt;
      &lt;td&gt;POINT (-2.59642 51.45944)&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th&gt;2094196650&lt;/th&gt;
      &lt;td&gt;51.482695&lt;/td&gt;
      &lt;td&gt;-2.538694&lt;/td&gt;
      &lt;td&gt;2&lt;/td&gt;
      &lt;td&gt;NaN&lt;/td&gt;
      &lt;td&gt;NaN&lt;/td&gt;
      &lt;td&gt;POINT (-2.53869 51.48270)&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th&gt;2424544775&lt;/th&gt;
      &lt;td&gt;51.413646&lt;/td&gt;
      &lt;td&gt;-2.571651&lt;/td&gt;
      &lt;td&gt;2&lt;/td&gt;
      &lt;td&gt;NaN&lt;/td&gt;
      &lt;td&gt;NaN&lt;/td&gt;
      &lt;td&gt;POINT (-2.57165 51.41365)&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th&gt;2488740793&lt;/th&gt;
      &lt;td&gt;51.483134&lt;/td&gt;
      &lt;td&gt;-2.767173&lt;/td&gt;
      &lt;td&gt;2&lt;/td&gt;
      &lt;td&gt;NaN&lt;/td&gt;
      &lt;td&gt;NaN&lt;/td&gt;
      &lt;td&gt;POINT (-2.76717 51.48313)&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th&gt;2914306154&lt;/th&gt;
      &lt;td&gt;51.502744&lt;/td&gt;
      &lt;td&gt;-2.558880&lt;/td&gt;
      &lt;td&gt;1&lt;/td&gt;
      &lt;td&gt;NaN&lt;/td&gt;
      &lt;td&gt;NaN&lt;/td&gt;
      &lt;td&gt;POINT (-2.55888 51.50274)&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;# get the node id&#39;s to flow data
# create two seperate data the target origins and target destinations with the XY coordinates
flows_full = flows.merge(pois.loc[:, pois.columns != &#39;geometry&#39;], left_on = &#39;origin&#39;, right_on = &#39;ID_code&#39;, how = &#39;left&#39;)

# lets just rename everything for the sake of clarity
flows_full = flows_full.merge(pois.loc[:, pois.columns != &#39;geometry&#39;], left_on = &#39;destination&#39;, right_on = &#39;ID_code&#39;, how = &#39;left&#39;).rename(columns = {&#39;NX_node_x&#39;:&#39;node_o&#39;,&#39;NX_node_y&#39;:&#39;node_d&#39;, &#39;X_x&#39;:&#39;X_o&#39;,&#39;Y_x&#39;:&#39;Y_o&#39;, &#39;X_y&#39;:&#39;X_d&#39;,&#39;Y_y&#39;:&#39;Y_d&#39;, &#39;ID_code_x&#39;:&#39;ID_code_o&#39;, &#39;ID_code_y&#39;:&#39;ID_code_d&#39;})

flows_full.head()
&lt;/code&gt;&lt;/pre&gt;
&lt;div&gt;
&lt;style scoped&gt;
    .dataframe tbody tr th:only-of-type {
        vertical-align: middle;
    }
&lt;pre&gt;&lt;code&gt;.dataframe tbody tr th {
    vertical-align: top;
}

.dataframe thead th {
    text-align: right;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;/style&gt;&lt;/p&gt;
&lt;table border=&#34;1&#34; class=&#34;dataframe&#34;&gt;
  &lt;thead&gt;
    &lt;tr style=&#34;text-align: right;&#34;&gt;
      &lt;th&gt;&lt;/th&gt;
      &lt;th&gt;origin&lt;/th&gt;
      &lt;th&gt;destination&lt;/th&gt;
      &lt;th&gt;ID_code_o&lt;/th&gt;
      &lt;th&gt;X_o&lt;/th&gt;
      &lt;th&gt;Y_o&lt;/th&gt;
      &lt;th&gt;node_o&lt;/th&gt;
      &lt;th&gt;ID_code_d&lt;/th&gt;
      &lt;th&gt;X_d&lt;/th&gt;
      &lt;th&gt;Y_d&lt;/th&gt;
      &lt;th&gt;node_d&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;th&gt;0&lt;/th&gt;
      &lt;td&gt;A91120&lt;/td&gt;
      &lt;td&gt;A91120&lt;/td&gt;
      &lt;td&gt;A91120&lt;/td&gt;
      &lt;td&gt;-2.559063&lt;/td&gt;
      &lt;td&gt;51.50283&lt;/td&gt;
      &lt;td&gt;2914306154&lt;/td&gt;
      &lt;td&gt;A91120&lt;/td&gt;
      &lt;td&gt;-2.559063&lt;/td&gt;
      &lt;td&gt;51.502830&lt;/td&gt;
      &lt;td&gt;2914306154&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th&gt;1&lt;/th&gt;
      &lt;td&gt;A91120&lt;/td&gt;
      &lt;td&gt;A99931&lt;/td&gt;
      &lt;td&gt;A91120&lt;/td&gt;
      &lt;td&gt;-2.559063&lt;/td&gt;
      &lt;td&gt;51.50283&lt;/td&gt;
      &lt;td&gt;2914306154&lt;/td&gt;
      &lt;td&gt;A99931&lt;/td&gt;
      &lt;td&gt;-2.596140&lt;/td&gt;
      &lt;td&gt;51.459182&lt;/td&gt;
      &lt;td&gt;1859320333&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th&gt;2&lt;/th&gt;
      &lt;td&gt;A91120&lt;/td&gt;
      &lt;td&gt;A99986&lt;/td&gt;
      &lt;td&gt;A91120&lt;/td&gt;
      &lt;td&gt;-2.559063&lt;/td&gt;
      &lt;td&gt;51.50283&lt;/td&gt;
      &lt;td&gt;2914306154&lt;/td&gt;
      &lt;td&gt;A99986&lt;/td&gt;
      &lt;td&gt;-2.538833&lt;/td&gt;
      &lt;td&gt;51.483143&lt;/td&gt;
      &lt;td&gt;2094196650&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th&gt;3&lt;/th&gt;
      &lt;td&gt;A91120&lt;/td&gt;
      &lt;td&gt;L81002&lt;/td&gt;
      &lt;td&gt;A91120&lt;/td&gt;
      &lt;td&gt;-2.559063&lt;/td&gt;
      &lt;td&gt;51.50283&lt;/td&gt;
      &lt;td&gt;2914306154&lt;/td&gt;
      &lt;td&gt;L81002&lt;/td&gt;
      &lt;td&gt;-2.930352&lt;/td&gt;
      &lt;td&gt;51.360207&lt;/td&gt;
      &lt;td&gt;317399984&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th&gt;4&lt;/th&gt;
      &lt;td&gt;A91120&lt;/td&gt;
      &lt;td&gt;L81004&lt;/td&gt;
      &lt;td&gt;A91120&lt;/td&gt;
      &lt;td&gt;-2.559063&lt;/td&gt;
      &lt;td&gt;51.50283&lt;/td&gt;
      &lt;td&gt;2914306154&lt;/td&gt;
      &lt;td&gt;L81004&lt;/td&gt;
      &lt;td&gt;-2.767317&lt;/td&gt;
      &lt;td&gt;51.482805&lt;/td&gt;
      &lt;td&gt;2488740793&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;h3 id=&#34;check-that-the-nodes-are-on-the-corect-place&#34;&gt;Check that the nodes are on the corect place&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;# check that the nodes are close to the points
plt.figure( figsize=(10,10))
fig = plt.plot()
ax = plt.axes()

nodes[nodes.index.isin(nodelist)].plot(ax=ax, markersize = 60, color=&amp;quot;b&amp;quot; )
pois.plot(ax=ax, markersize = 20, color=&amp;quot;r&amp;quot;)

plt.show();
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&#34;./pandana/pandana_17_1.png&#34; alt=&#34;png&#34;&gt;&lt;/p&gt;
&lt;p&gt;Looks fine to me&lt;/p&gt;
&lt;h3 id=&#34;apply-the-networkxshortest-path-length&#34;&gt;Apply the networkx.shortest_path_length&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;# define a function that calculates shortest path between the nodes on graph
def path_length(row):
    return nx.shortest_path_length(avon, row[&#39;node_o&#39;], row[&#39;node_d&#39;], weight=&#39;length&#39;)

# apply the function to our OD data
%timeit flows_full[&#39;path_length&#39;] = flows_full.apply(path_length, axis=1)
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;26.8 s ± 1.58 s per loop (mean ± std. dev. of 7 runs, 1 loop each)
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;# This is approximately
print(str(round((26.8*(7*1))/60,2)) + &#39; minutes&#39;)
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;3.13 minutes
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;flows_full.head()
&lt;/code&gt;&lt;/pre&gt;
&lt;div&gt;
&lt;style scoped&gt;
    .dataframe tbody tr th:only-of-type {
        vertical-align: middle;
    }
&lt;pre&gt;&lt;code&gt;.dataframe tbody tr th {
    vertical-align: top;
}

.dataframe thead th {
    text-align: right;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;/style&gt;&lt;/p&gt;
&lt;table border=&#34;1&#34; class=&#34;dataframe&#34;&gt;
  &lt;thead&gt;
    &lt;tr style=&#34;text-align: right;&#34;&gt;
      &lt;th&gt;&lt;/th&gt;
      &lt;th&gt;origin&lt;/th&gt;
      &lt;th&gt;destination&lt;/th&gt;
      &lt;th&gt;ID_code_o&lt;/th&gt;
      &lt;th&gt;X_o&lt;/th&gt;
      &lt;th&gt;Y_o&lt;/th&gt;
      &lt;th&gt;node_o&lt;/th&gt;
      &lt;th&gt;ID_code_d&lt;/th&gt;
      &lt;th&gt;X_d&lt;/th&gt;
      &lt;th&gt;Y_d&lt;/th&gt;
      &lt;th&gt;node_d&lt;/th&gt;
      &lt;th&gt;path_length&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;th&gt;0&lt;/th&gt;
      &lt;td&gt;A91120&lt;/td&gt;
      &lt;td&gt;A91120&lt;/td&gt;
      &lt;td&gt;A91120&lt;/td&gt;
      &lt;td&gt;-2.559063&lt;/td&gt;
      &lt;td&gt;51.50283&lt;/td&gt;
      &lt;td&gt;2914306154&lt;/td&gt;
      &lt;td&gt;A91120&lt;/td&gt;
      &lt;td&gt;-2.559063&lt;/td&gt;
      &lt;td&gt;51.502830&lt;/td&gt;
      &lt;td&gt;2914306154&lt;/td&gt;
      &lt;td&gt;0.000&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th&gt;1&lt;/th&gt;
      &lt;td&gt;A91120&lt;/td&gt;
      &lt;td&gt;A99931&lt;/td&gt;
      &lt;td&gt;A91120&lt;/td&gt;
      &lt;td&gt;-2.559063&lt;/td&gt;
      &lt;td&gt;51.50283&lt;/td&gt;
      &lt;td&gt;2914306154&lt;/td&gt;
      &lt;td&gt;A99931&lt;/td&gt;
      &lt;td&gt;-2.596140&lt;/td&gt;
      &lt;td&gt;51.459182&lt;/td&gt;
      &lt;td&gt;1859320333&lt;/td&gt;
      &lt;td&gt;6960.514&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th&gt;2&lt;/th&gt;
      &lt;td&gt;A91120&lt;/td&gt;
      &lt;td&gt;A99986&lt;/td&gt;
      &lt;td&gt;A91120&lt;/td&gt;
      &lt;td&gt;-2.559063&lt;/td&gt;
      &lt;td&gt;51.50283&lt;/td&gt;
      &lt;td&gt;2914306154&lt;/td&gt;
      &lt;td&gt;A99986&lt;/td&gt;
      &lt;td&gt;-2.538833&lt;/td&gt;
      &lt;td&gt;51.483143&lt;/td&gt;
      &lt;td&gt;2094196650&lt;/td&gt;
      &lt;td&gt;4333.457&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th&gt;3&lt;/th&gt;
      &lt;td&gt;A91120&lt;/td&gt;
      &lt;td&gt;L81002&lt;/td&gt;
      &lt;td&gt;A91120&lt;/td&gt;
      &lt;td&gt;-2.559063&lt;/td&gt;
      &lt;td&gt;51.50283&lt;/td&gt;
      &lt;td&gt;2914306154&lt;/td&gt;
      &lt;td&gt;L81002&lt;/td&gt;
      &lt;td&gt;-2.930352&lt;/td&gt;
      &lt;td&gt;51.360207&lt;/td&gt;
      &lt;td&gt;317399984&lt;/td&gt;
      &lt;td&gt;36334.316&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th&gt;4&lt;/th&gt;
      &lt;td&gt;A91120&lt;/td&gt;
      &lt;td&gt;L81004&lt;/td&gt;
      &lt;td&gt;A91120&lt;/td&gt;
      &lt;td&gt;-2.559063&lt;/td&gt;
      &lt;td&gt;51.50283&lt;/td&gt;
      &lt;td&gt;2914306154&lt;/td&gt;
      &lt;td&gt;L81004&lt;/td&gt;
      &lt;td&gt;-2.767317&lt;/td&gt;
      &lt;td&gt;51.482805&lt;/td&gt;
      &lt;td&gt;2488740793&lt;/td&gt;
      &lt;td&gt;19754.732&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;h2 id=&#34;using-pandana&#34;&gt;Using Pandana&lt;/h2&gt;
&lt;h3 id=&#34;load-the-graph&#34;&gt;Load the graph&lt;/h3&gt;
&lt;p&gt;Listen, I have tried to use the osm loader inside the pandana, but it took ages. after 2 hours of loading, I decided it will be easier to get the previously loaded osm graph with osmnx and use that as a base for the pandana graph. You can just simply use the geodataframes of nodes and flows for the base of your graph.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;# reset index so our origins and destinations are not in idnex
edges = edges.reset_index()

# create network with pandana
avon_pan = pandana.Network(nodes[&#39;x&#39;], nodes[&#39;y&#39;], 
                          edges[&#39;u&#39;], edges[&#39;v&#39;], edges[[&#39;length&#39;]])
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&#34;find-the-nearest-nodes-to-our-points-in-pandana-graph&#34;&gt;Find the nearest nodes to our points in pandana graph&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;# we are going to define the origins and destinations separately as alist
# get_node_ids uses kdtree writen in c++, google it its like a magic

origin_nodes = avon_pan.get_node_ids(flows_full.X_o, flows_full.Y_o).values


dests_nodes = avon_pan.get_node_ids(flows_full.X_d, flows_full.Y_d).values
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;flows_full.head()
&lt;/code&gt;&lt;/pre&gt;
&lt;div&gt;
&lt;style scoped&gt;
    .dataframe tbody tr th:only-of-type {
        vertical-align: middle;
    }
&lt;pre&gt;&lt;code&gt;.dataframe tbody tr th {
    vertical-align: top;
}

.dataframe thead th {
    text-align: right;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;/style&gt;&lt;/p&gt;
&lt;table border=&#34;1&#34; class=&#34;dataframe&#34;&gt;
  &lt;thead&gt;
    &lt;tr style=&#34;text-align: right;&#34;&gt;
      &lt;th&gt;&lt;/th&gt;
      &lt;th&gt;origin&lt;/th&gt;
      &lt;th&gt;destination&lt;/th&gt;
      &lt;th&gt;ID_code_o&lt;/th&gt;
      &lt;th&gt;X_o&lt;/th&gt;
      &lt;th&gt;Y_o&lt;/th&gt;
      &lt;th&gt;node_o&lt;/th&gt;
      &lt;th&gt;ID_code_d&lt;/th&gt;
      &lt;th&gt;X_d&lt;/th&gt;
      &lt;th&gt;Y_d&lt;/th&gt;
      &lt;th&gt;node_d&lt;/th&gt;
      &lt;th&gt;path_length&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;th&gt;0&lt;/th&gt;
      &lt;td&gt;A91120&lt;/td&gt;
      &lt;td&gt;A91120&lt;/td&gt;
      &lt;td&gt;A91120&lt;/td&gt;
      &lt;td&gt;-2.559063&lt;/td&gt;
      &lt;td&gt;51.50283&lt;/td&gt;
      &lt;td&gt;2914306154&lt;/td&gt;
      &lt;td&gt;A91120&lt;/td&gt;
      &lt;td&gt;-2.559063&lt;/td&gt;
      &lt;td&gt;51.502830&lt;/td&gt;
      &lt;td&gt;2914306154&lt;/td&gt;
      &lt;td&gt;0.000&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th&gt;1&lt;/th&gt;
      &lt;td&gt;A91120&lt;/td&gt;
      &lt;td&gt;A99931&lt;/td&gt;
      &lt;td&gt;A91120&lt;/td&gt;
      &lt;td&gt;-2.559063&lt;/td&gt;
      &lt;td&gt;51.50283&lt;/td&gt;
      &lt;td&gt;2914306154&lt;/td&gt;
      &lt;td&gt;A99931&lt;/td&gt;
      &lt;td&gt;-2.596140&lt;/td&gt;
      &lt;td&gt;51.459182&lt;/td&gt;
      &lt;td&gt;1859320333&lt;/td&gt;
      &lt;td&gt;6960.514&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th&gt;2&lt;/th&gt;
      &lt;td&gt;A91120&lt;/td&gt;
      &lt;td&gt;A99986&lt;/td&gt;
      &lt;td&gt;A91120&lt;/td&gt;
      &lt;td&gt;-2.559063&lt;/td&gt;
      &lt;td&gt;51.50283&lt;/td&gt;
      &lt;td&gt;2914306154&lt;/td&gt;
      &lt;td&gt;A99986&lt;/td&gt;
      &lt;td&gt;-2.538833&lt;/td&gt;
      &lt;td&gt;51.483143&lt;/td&gt;
      &lt;td&gt;2094196650&lt;/td&gt;
      &lt;td&gt;4333.457&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th&gt;3&lt;/th&gt;
      &lt;td&gt;A91120&lt;/td&gt;
      &lt;td&gt;L81002&lt;/td&gt;
      &lt;td&gt;A91120&lt;/td&gt;
      &lt;td&gt;-2.559063&lt;/td&gt;
      &lt;td&gt;51.50283&lt;/td&gt;
      &lt;td&gt;2914306154&lt;/td&gt;
      &lt;td&gt;L81002&lt;/td&gt;
      &lt;td&gt;-2.930352&lt;/td&gt;
      &lt;td&gt;51.360207&lt;/td&gt;
      &lt;td&gt;317399984&lt;/td&gt;
      &lt;td&gt;36334.316&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th&gt;4&lt;/th&gt;
      &lt;td&gt;A91120&lt;/td&gt;
      &lt;td&gt;L81004&lt;/td&gt;
      &lt;td&gt;A91120&lt;/td&gt;
      &lt;td&gt;-2.559063&lt;/td&gt;
      &lt;td&gt;51.50283&lt;/td&gt;
      &lt;td&gt;2914306154&lt;/td&gt;
      &lt;td&gt;L81004&lt;/td&gt;
      &lt;td&gt;-2.767317&lt;/td&gt;
      &lt;td&gt;51.482805&lt;/td&gt;
      &lt;td&gt;2488740793&lt;/td&gt;
      &lt;td&gt;19754.732&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;h3 id=&#34;calculate-distances-using-pandana-shortest-path-lengths&#34;&gt;Calculate distances using pandana &amp;lsquo;shortest_path_lengths&amp;rsquo;&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;%%time
flows_full[&#39;distances&#39;] = pd.Series(avon_pan.shortest_path_lengths(origin_nodes, dests_nodes))
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;Wall time: 144 ms
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;# How much faster is this from networkx
(((3.13*60)*1000))/(144)
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;1304.1666666666665
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is more than 1000times faster!&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;flows_full.head()
&lt;/code&gt;&lt;/pre&gt;
&lt;div&gt;
&lt;style scoped&gt;
    .dataframe tbody tr th:only-of-type {
        vertical-align: middle;
    }
&lt;pre&gt;&lt;code&gt;.dataframe tbody tr th {
    vertical-align: top;
}

.dataframe thead th {
    text-align: right;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;/style&gt;&lt;/p&gt;
&lt;table border=&#34;1&#34; class=&#34;dataframe&#34;&gt;
  &lt;thead&gt;
    &lt;tr style=&#34;text-align: right;&#34;&gt;
      &lt;th&gt;&lt;/th&gt;
      &lt;th&gt;origin&lt;/th&gt;
      &lt;th&gt;destination&lt;/th&gt;
      &lt;th&gt;ID_code_o&lt;/th&gt;
      &lt;th&gt;X_o&lt;/th&gt;
      &lt;th&gt;Y_o&lt;/th&gt;
      &lt;th&gt;node_o&lt;/th&gt;
      &lt;th&gt;ID_code_d&lt;/th&gt;
      &lt;th&gt;X_d&lt;/th&gt;
      &lt;th&gt;Y_d&lt;/th&gt;
      &lt;th&gt;node_d&lt;/th&gt;
      &lt;th&gt;path_length&lt;/th&gt;
      &lt;th&gt;distances&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;th&gt;0&lt;/th&gt;
      &lt;td&gt;A91120&lt;/td&gt;
      &lt;td&gt;A91120&lt;/td&gt;
      &lt;td&gt;A91120&lt;/td&gt;
      &lt;td&gt;-2.559063&lt;/td&gt;
      &lt;td&gt;51.50283&lt;/td&gt;
      &lt;td&gt;2914306154&lt;/td&gt;
      &lt;td&gt;A91120&lt;/td&gt;
      &lt;td&gt;-2.559063&lt;/td&gt;
      &lt;td&gt;51.502830&lt;/td&gt;
      &lt;td&gt;2914306154&lt;/td&gt;
      &lt;td&gt;0.000&lt;/td&gt;
      &lt;td&gt;0.000&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th&gt;1&lt;/th&gt;
      &lt;td&gt;A91120&lt;/td&gt;
      &lt;td&gt;A99931&lt;/td&gt;
      &lt;td&gt;A91120&lt;/td&gt;
      &lt;td&gt;-2.559063&lt;/td&gt;
      &lt;td&gt;51.50283&lt;/td&gt;
      &lt;td&gt;2914306154&lt;/td&gt;
      &lt;td&gt;A99931&lt;/td&gt;
      &lt;td&gt;-2.596140&lt;/td&gt;
      &lt;td&gt;51.459182&lt;/td&gt;
      &lt;td&gt;1859320333&lt;/td&gt;
      &lt;td&gt;6960.514&lt;/td&gt;
      &lt;td&gt;6960.508&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th&gt;2&lt;/th&gt;
      &lt;td&gt;A91120&lt;/td&gt;
      &lt;td&gt;A99986&lt;/td&gt;
      &lt;td&gt;A91120&lt;/td&gt;
      &lt;td&gt;-2.559063&lt;/td&gt;
      &lt;td&gt;51.50283&lt;/td&gt;
      &lt;td&gt;2914306154&lt;/td&gt;
      &lt;td&gt;A99986&lt;/td&gt;
      &lt;td&gt;-2.538833&lt;/td&gt;
      &lt;td&gt;51.483143&lt;/td&gt;
      &lt;td&gt;2094196650&lt;/td&gt;
      &lt;td&gt;4333.457&lt;/td&gt;
      &lt;td&gt;4333.454&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th&gt;3&lt;/th&gt;
      &lt;td&gt;A91120&lt;/td&gt;
      &lt;td&gt;L81002&lt;/td&gt;
      &lt;td&gt;A91120&lt;/td&gt;
      &lt;td&gt;-2.559063&lt;/td&gt;
      &lt;td&gt;51.50283&lt;/td&gt;
      &lt;td&gt;2914306154&lt;/td&gt;
      &lt;td&gt;L81002&lt;/td&gt;
      &lt;td&gt;-2.930352&lt;/td&gt;
      &lt;td&gt;51.360207&lt;/td&gt;
      &lt;td&gt;317399984&lt;/td&gt;
      &lt;td&gt;36334.316&lt;/td&gt;
      &lt;td&gt;36334.302&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th&gt;4&lt;/th&gt;
      &lt;td&gt;A91120&lt;/td&gt;
      &lt;td&gt;L81004&lt;/td&gt;
      &lt;td&gt;A91120&lt;/td&gt;
      &lt;td&gt;-2.559063&lt;/td&gt;
      &lt;td&gt;51.50283&lt;/td&gt;
      &lt;td&gt;2914306154&lt;/td&gt;
      &lt;td&gt;L81004&lt;/td&gt;
      &lt;td&gt;-2.767317&lt;/td&gt;
      &lt;td&gt;51.482805&lt;/td&gt;
      &lt;td&gt;2488740793&lt;/td&gt;
      &lt;td&gt;19754.732&lt;/td&gt;
      &lt;td&gt;19754.729&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;p&gt;The distances seems to be satisfying but are we sure that the packages picked up the same nodes?&lt;/p&gt;
&lt;h3 id=&#34;check-that-the-nodes-are-the-same-as-those-from-networkx&#34;&gt;Check that the nodes are the same as those from NetworkX&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;x = origin_nodes == flows_full[&#39;node_o&#39;]
x.describe()

&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;count       36
unique       1
top       True
freq        36
Name: node_o, dtype: object
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;y = dests_nodes == flows_full[&#39;node_d&#39;]
y.describe()
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;count       36
unique       1
top       True
freq        36
Name: node_d, dtype: object
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This looks spot on.&lt;/p&gt;
&lt;h2 id=&#34;appendix&#34;&gt;Appendix&lt;/h2&gt;
&lt;h3 id=&#34;google-colab&#34;&gt;Google Colab&lt;/h3&gt;
&lt;p&gt;If you want to run this on Google Colab, you need to install&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Geopandas&lt;/li&gt;
&lt;li&gt;OsmnX&lt;/li&gt;
&lt;li&gt;Matplotlib&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;# install Geopandas
# Important library for many geopython libraries
!apt install gdal-bin python-gdal python3-gdal 
# Install rtree - Geopandas requirment
!apt install python3-rtree 
# Install Geopandas
!pip install git+git://github.com/geopandas/geopandas.git
# Install descartes - Geopandas requirment
!pip install descartes 
# Install Folium for Geographic data visualization
!pip install folium
# Install plotlyExpress
!pip install plotly_express# install packages
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;# osmnx
# this gives errors but works ...no idea
!apt-get -qq install -y libspatialindex-dev &amp;amp;&amp;amp; pip install -q -U osmnx 
ox.config(use_cache=True, log_console=True)
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;!python -m pip uninstall matplotlib
!pip install matplotlib==3.1.3# mount the drive
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&#34;environment-set-up&#34;&gt;Environment set up&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;name: graphs
channels:
  - conda-forge
  - defaults
dependencies:
  - _r-mutex=1.0.1=anacondar_1
  - anyio=2.2.0=py39hcbf5309_0
  - argon2-cffi=20.1.0=py39hb82d6ee_2
  - async_generator=1.10=py_0
  - attrs=20.3.0=pyhd3deb0d_0
  - babel=2.9.0=pyhd3deb0d_0
  - backcall=0.2.0=pyh9f0ad1d_0
  - backports=1.0=py_2
  - backports.functools_lru_cache=1.6.1=py_0
  - bleach=3.3.0=pyh44b312d_0
  - blosc=1.21.0=h0e60522_0
  - boost-cpp=1.74.0=h54f0996_2
  - branca=0.4.2=pyhd8ed1ab_0
  - brotlipy=0.7.0=py39hb82d6ee_1001
  - bzip2=1.0.8=h8ffe710_4
  - ca-certificates=2020.12.5=h5b45459_0
  - cairo=1.16.0=hba8bd2f_1007
  - certifi=2020.12.5=py39hcbf5309_1
  - cffi=1.14.5=py39h0878f49_0
  - cfitsio=3.470=h0af3d06_7
  - chardet=4.0.0=py39hcbf5309_1
  - click=7.1.2=pyh9f0ad1d_0
  - click-plugins=1.1.1=py_0
  - cligj=0.7.1=pyhd8ed1ab_0
  - colorama=0.4.4=pyh9f0ad1d_0
  - cryptography=3.4.6=py39hd8d06c1_0
  - curl=7.75.0=hf1763fc_0
  - cycler=0.10.0=py_2
  - decorator=4.4.2=py_0
  - defusedxml=0.7.1=pyhd8ed1ab_0
  - descartes=1.1.0=py_4
  - entrypoints=0.3=pyhd8ed1ab_1003
  - expat=2.2.10=h39d44d4_0
  - fiona=1.8.18=py39h9f1b043_1
  - folium=0.12.0=pyhd8ed1ab_0
  - fontconfig=2.13.1=h1989441_1004
  - freetype=2.10.4=h546665d_1
  - freexl=1.0.5=hd288d7e_1002
  - gdal=3.2.2=py39h6795fcd_0
  - geopandas=0.9.0=pyhd8ed1ab_0
  - geos=3.9.1=h39d44d4_2
  - geotiff=1.6.0=h8e90983_5
  - gettext=0.19.8.1=h1a89ca6_1005
  - hdf4=4.2.13=h0e5069d_1004
  - hdf5=1.10.6=nompi_h5268f04_1114
  - icu=68.1=h0e60522_0
  - idna=2.10=pyh9f0ad1d_0
  - importlib-metadata=3.7.2=py39hcbf5309_0
  - intel-openmp=2020.3=h57928b3_311
  - ipykernel=5.5.0=py39h832f523_1
  - ipython=7.21.0=py39h832f523_0
  - ipython_genutils=0.2.0=py_1
  - jedi=0.18.0=py39hcbf5309_2
  - jinja2=2.11.3=pyh44b312d_0
  - joblib=1.0.1=pyhd8ed1ab_0
  - jpeg=9d=h8ffe710_0
  - json5=0.9.5=pyh9f0ad1d_0
  - jsonschema=3.2.0=pyhd8ed1ab_3
  - jupyter-packaging=0.7.12=pyhd8ed1ab_0
  - jupyter_client=6.1.11=pyhd8ed1ab_1
  - jupyter_core=4.7.1=py39hcbf5309_0
  - jupyter_server=1.4.1=py39hcbf5309_0
  - jupyterlab=3.0.10=pyhd8ed1ab_0
  - jupyterlab_pygments=0.1.2=pyh9f0ad1d_0
  - jupyterlab_server=2.3.0=pyhd8ed1ab_0
  - kealib=1.4.14=h96bfa42_2
  - kiwisolver=1.3.1=py39h2e07f2f_1
  - krb5=1.17.2=hbae68bd_0
  - lcms2=2.12=h2a16943_0
  - libblas=3.9.0=8_mkl
  - libcblas=3.9.0=8_mkl
  - libcurl=7.75.0=hf1763fc_0
  - libffi=3.3=h0e60522_2
  - libgdal=3.2.2=hbe61683_0
  - libglib=2.66.7=h1e62bf3_1
  - libiconv=1.16=he774522_0
  - libkml=1.3.0=h02ac0ef_1012
  - liblapack=3.9.0=8_mkl
  - libnetcdf=4.7.4=nompi_h3a9aa94_107
  - libpng=1.6.37=h1d00b33_2
  - libpq=13.1=h4f54205_2
  - librttopo=1.1.0=hb340de5_6
  - libsodium=1.0.18=h8d14728_1
  - libspatialindex=1.9.3=h39d44d4_3
  - libspatialite=5.0.1=h6b539a6_4
  - libssh2=1.9.0=h680486a_6
  - libtiff=4.2.0=hc10be44_0
  - libwebp-base=1.2.0=h8ffe710_0
  - libxml2=2.9.10=hf5bbc77_3
  - lz4-c=1.9.3=h8ffe710_0
  - m2w64-bwidget=1.9.10=2
  - m2w64-bzip2=1.0.6=6
  - m2w64-expat=2.1.1=2
  - m2w64-fftw=3.3.4=6
  - m2w64-flac=1.3.1=3
  - m2w64-gcc-libgfortran=5.3.0=6
  - m2w64-gcc-libs=5.3.0=7
  - m2w64-gcc-libs-core=5.3.0=7
  - m2w64-gettext=0.19.7=2
  - m2w64-gmp=6.1.0=2
  - m2w64-gsl=2.1=2
  - m2w64-libiconv=1.14=6
  - m2w64-libjpeg-turbo=1.4.2=3
  - m2w64-libogg=1.3.2=3
  - m2w64-libpng=1.6.21=2
  - m2w64-libsndfile=1.0.26=2
  - m2w64-libtiff=4.0.6=2
  - m2w64-libvorbis=1.3.5=2
  - m2w64-libwinpthread-git=5.0.0.4634.697f757=2
  - m2w64-libxml2=2.9.3=3
  - m2w64-mpfr=3.1.4=4
  - m2w64-pcre2=10.34=0
  - m2w64-speex=1.2rc2=3
  - m2w64-speexdsp=1.2rc3=3
  - m2w64-tcl=8.6.5=3
  - m2w64-tk=8.6.5=3
  - m2w64-tktable=2.10=5
  - m2w64-wineditline=2.101=5
  - m2w64-xz=5.2.2=2
  - m2w64-zlib=1.2.8=10
  - markupsafe=1.1.1=py39hb82d6ee_3
  - matplotlib-base=3.3.4=py39h581301d_0
  - mistune=0.8.4=py39hb82d6ee_1003
  - mkl=2020.4=hb70f87d_311
  - mock=4.0.3=py39hcbf5309_1
  - msys2-conda-epoch=20160418=1
  - munch=2.5.0=py_0
  - nbclassic=0.2.6=pyhd8ed1ab_0
  - nbclient=0.5.3=pyhd8ed1ab_0
  - nbconvert=6.0.7=py39hcbf5309_3
  - nbformat=5.1.2=pyhd8ed1ab_1
  - nest-asyncio=1.4.3=pyhd8ed1ab_0
  - networkx=2.5=py_0
  - notebook=6.2.0=py39hcbf5309_0
  - numexpr=2.7.3=py39h2e25243_0
  - numpy=1.20.1=py39h6635163_0
  - olefile=0.46=pyh9f0ad1d_1
  - openjpeg=2.4.0=h48faf41_0
  - openssl=1.1.1j=h8ffe710_0
  - osmnx=1.0.1=pyhd3deb0d_0
  - packaging=20.9=pyh44b312d_0
  - pandana=0.6=py39h2e25243_0
  - pandas=1.2.3=py39h2e25243_0
  - pandoc=2.12=h8ffe710_0
  - pandocfilters=1.4.2=py_1
  - parso=0.8.1=pyhd8ed1ab_0
  - pcre=8.44=ha925a31_0
  - pickleshare=0.7.5=py_1003
  - pillow=8.1.2=py39h1a9d4f7_0
  - pip=21.0.1=pyhd8ed1ab_0
  - pixman=0.40.0=h8ffe710_0
  - poppler=21.03.0=h9ff6ed8_0
  - poppler-data=0.4.10=0
  - postgresql=13.1=h0f1a9bc_2
  - proj=8.0.0=h1cfcee9_0
  - prometheus_client=0.9.0=pyhd3deb0d_0
  - prompt-toolkit=3.0.16=pyha770c72_0
  - pycparser=2.20=pyh9f0ad1d_2
  - pygments=2.8.1=pyhd8ed1ab_0
  - pyopenssl=20.0.1=pyhd8ed1ab_0
  - pyparsing=2.4.7=pyh9f0ad1d_0
  - pyproj=3.0.1=py39h1007a03_1
  - pyrsistent=0.17.3=py39hb82d6ee_2
  - pysocks=1.7.1=py39hcbf5309_3
  - pytables=3.6.1=py39h42e6cd8_3
  - python=3.9.2=h7840368_0_cpython
  - python-dateutil=2.8.1=py_0
  - python_abi=3.9=1_cp39
  - pytz=2021.1=pyhd8ed1ab_0
  - pywin32=300=py39hb82d6ee_0
  - pywinpty=0.5.7=py39hde42818_1
  - pyzmq=22.0.3=py39he46f08e_1
  - r-base=4.0.3=hddad469_7
  - r-iterators=1.0.13=r40h142f84f_0
  - r-itertools=0.1_3=r40_1003
  - requests=2.25.1=pyhd3deb0d_0
  - rtree=0.9.7=py39h09fdee3_1
  - scikit-learn=0.24.1=py39he931e04_0
  - scipy=1.6.0=py39hc0c34ad_0
  - send2trash=1.5.0=py_0
  - setuptools=49.6.0=py39hcbf5309_3
  - shapely=1.7.1=py39h90c6b7e_4
  - six=1.15.0=pyh9f0ad1d_0
  - sniffio=1.2.0=py39hcbf5309_1
  - sqlite=3.34.0=h8ffe710_0
  - terminado=0.9.2=py39hcbf5309_0
  - testpath=0.4.4=py_0
  - threadpoolctl=2.1.0=pyh5ca1d4c_0
  - tiledb=2.2.4=hddc2a84_2
  - tk=8.6.10=h8ffe710_1
  - tornado=6.1=py39hb82d6ee_1
  - traitlets=5.0.5=py_0
  - tzdata=2021a=he74cb21_0
  - urllib3=1.26.3=pyhd8ed1ab_0
  - vc=14.2=hb210afc_4
  - vs2015_runtime=14.28.29325=h5e1d092_4
  - wcwidth=0.2.5=pyh9f0ad1d_2
  - webencodings=0.5.1=py_1
  - wheel=0.36.2=pyhd3deb0d_0
  - win_inet_pton=1.1.0=py39hcbf5309_2
  - wincertstore=0.2=py39hcbf5309_1006
  - winpty=0.4.3=4
  - xerces-c=3.2.3=h0e60522_2
  - xz=5.2.5=h62dcd97_1
  - zeromq=4.3.4=h0e60522_0
  - zipp=3.4.1=pyhd8ed1ab_0
  - zlib=1.2.11=h62dcd97_1010
  - zstd=1.4.9=h6255e5f_0

&lt;/code&gt;&lt;/pre&gt;
</description>
    </item>
    
  </channel>
</rss>
