def mkDfNodeAttribs(G): latCentroid, lngCentroid = utils.calcCentroidOfStops(G) ndAttribsVsR = [] for node in G.nodes: lng = G.nodes[node][const.GNodeAttribs.Lng.name] lat = G.nodes[node][const.GNodeAttribs.Lat.name] ndAttribsVsR.append([ node, utils.calcGeodesicDist([lng, lat], [lngCentroid, latCentroid]) / 1000, # in km lat, lng, G.nodes[node][const.GNodeAttribs.totDeg.name], G.nodes[node][const.GNodeAttribs.nLines.name], G.nodes[node][const.GNodeAttribs.nServices.name], G.nodes[node][const.GNodeAttribs.cbHops.name], G.nodes[node][const.GNodeAttribs.cbDist.name], G.nodes[node][const.GNodeAttribs.cbTime.name], G.nodes[node][const.GNodeAttribs.toV_u30.name], G.nodes[node][const.GNodeAttribs.frV_u30.name], G.nodes[node][const.GNodeAttribs.toV_3060.name], G.nodes[node][const.GNodeAttribs.frV_3060.name], G.nodes[node][const.GNodeAttribs.toV_6090.name], G.nodes[node][const.GNodeAttribs.frV_6090.name], G.nodes[node][const.GNodeAttribs.toV_o90.name], G.nodes[node][const.GNodeAttribs.frV_o90.name], G.nodes[node][const.GNodeAttribs.toV_u60.name], G.nodes[node][const.GNodeAttribs.frV_u60.name], G.nodes[node][const.GNodeAttribs.toV_u90.name], G.nodes[node][const.GNodeAttribs.frV_u90.name], G.nodes[node][const.GNodeAttribs.ndtoV_u30.name], G.nodes[node][const.GNodeAttribs.ndfrV_u30.name], G.nodes[node][const.GNodeAttribs.ndtoV_3060.name], G.nodes[node][const.GNodeAttribs.ndfrV_3060.name], G.nodes[node][const.GNodeAttribs.ndtoV_6090.name], G.nodes[node][const.GNodeAttribs.ndfrV_6090.name], G.nodes[node][const.GNodeAttribs.ndtoV_o90.name], G.nodes[node][const.GNodeAttribs.ndfrV_o90.name], G.nodes[node][const.GNodeAttribs.ndtoV_u60.name], G.nodes[node][const.GNodeAttribs.ndfrV_u60.name], G.nodes[node][const.GNodeAttribs.ndtoV_u90.name], G.nodes[node][const.GNodeAttribs.ndfrV_u90.name] ]) df = pd.DataFrame(ndAttribsVsR, columns=[ 'StationId', 'R', 'Lat', 'Lng', 'totDeg', 'nLines', 'nServices', 'cbHops', 'cbDist', 'cbTime', 'toV_u30', 'frV_u30', 'toV_3060', 'frV_3060', 'toV_6090', 'frV_6090', 'toV_o90', 'frV_o90', 'toV_u60', 'frV_u60', 'toV_u90', 'frV_u90', 'ndtoV_u30', 'ndfrV_u30', 'ndtoV_3060', 'ndfrV_3060', 'ndtoV_6090', 'ndfrV_6090', 'ndtoV_o90', 'ndfrV_o90', 'ndtoV_u60', 'ndfrV_u60', 'ndtoV_u90', 'ndfrV_u90' ]) # df.to_csv('%s/nodeCentrals/proxDensVsR.csv' % const.outputsFolder, index=False) df['range'] = df['R'].apply(utils.getRange) return df
def calcTargetClosenessCentrality(G, shortHops, shortDist, shortTime): ''' calculates normalised closeness centralities by target from results of shortest distances - ignoring identical nodes - ignoring nodes within walk distance to each other Run of BUDF :param G: :param shortHops: :param shortDist: :param shortTime: :return: ''' lenKey = 0 pathKey = 1 distTo = [] for jNode in G.nodes(): lenHops = 0 lenDist = 0 lenTime = 0 for iNode in G.nodes(): if iNode == jNode: continue nodeiCoord = [ G.nodes[iNode][const.GNodeAttribs.Lng.name], G.nodes[iNode][const.GNodeAttribs.Lat.name] ] nodejCoord = [ G.nodes[jNode][const.GNodeAttribs.Lng.name], G.nodes[jNode][const.GNodeAttribs.Lat.name] ] dist = utils.calcGeodesicDist(nodeiCoord, nodejCoord) # distance in metres if dist <= const.maxWalkDist: continue lenHops += shortHops[iNode][lenKey][jNode] lenDist += shortDist[iNode][lenKey][jNode] lenTime += shortTime[iNode][lenKey][jNode] distTo.append([jNode, lenHops, lenDist, lenTime]) dfDistTo = pd.DataFrame(distTo, columns=['node', 'lenHops', 'lenDist', 'lenTime']) dfDistTo['lenHopsNorm'] = dfDistTo['lenHops'].apply( lambda x: len(G.nodes) / x) dfDistTo['lenDistNorm'] = dfDistTo['lenDist'].apply( lambda x: len(G.nodes) / x) dfDistTo['lenTimeNorm'] = dfDistTo['lenTime'].apply( lambda x: len(G.nodes) / x) return dfDistTo
def calcNearbyNodes(G): for inode in G.nodes: nodeiCoord = [ G.nodes[inode][const.GNodeAttribs.Lng.name], G.nodes[inode][const.GNodeAttribs.Lat.name] ] neighbours = [] for jnode in G.nodes: if jnode == inode: continue nodejCoord = [ G.nodes[jnode][const.GNodeAttribs.Lng.name], G.nodes[jnode][const.GNodeAttribs.Lat.name] ] dist = utils.calcGeodesicDist(nodeiCoord, nodejCoord) # distance in metres if dist <= const.maxWalkDist: neighbours.append(jnode) G.nodes[inode][const.GNodeAttribs.neighbourNodes.name] = neighbours
def calcBetweennessCentrality(G, shortHops, shortDist, shortTime): ''' calculates betweenness centrality for all pair of nodes that are - not identical - not within walk distance to each other :param shortHops: :param shortDist: :param shortTime: :return: ''' lenKey = 0 pathKey = 1 cb = [] for node in G.nodes: ndCbHops = 0 ndCbDist = 0 ndCbTime = 0 for iNode in G.nodes: if iNode == node: continue for jNode in G.nodes(): if jNode == node or jNode == iNode: continue nodeiCoord = [ G.nodes[iNode][const.GNodeAttribs.Lng.name], G.nodes[iNode][const.GNodeAttribs.Lat.name] ] nodejCoord = [ G.nodes[jNode][const.GNodeAttribs.Lng.name], G.nodes[jNode][const.GNodeAttribs.Lat.name] ] dist = utils.calcGeodesicDist(nodeiCoord, nodejCoord) # distance in metres if dist <= const.maxWalkDist: continue sPathHops = shortHops[iNode][pathKey][jNode] sPathDist = shortDist[iNode][pathKey][jNode] sPathTime = shortTime[iNode][pathKey][jNode] if node in sPathHops: ndCbHops += 1 if node in sPathDist: ndCbDist += 1 if node in sPathTime: ndCbTime += 1 cb.append([node, ndCbHops, ndCbDist, ndCbTime]) dfCb = pd.DataFrame(cb, columns=['node', 'cbHops', 'cbDist', 'cbTime']) cbHopsMax = dfCb['CbHops'].max() cbHopsMin = dfCb['CbHops'].min() cbDistMax = dfCb['CbDist'].max() cbDistMin = dfCb['CbDist'].min() cbTimeMax = dfCb['CbTime'].max() cbTimeMin = dfCb['CbTime'].min() dfCb['cbHopsNorm'] = dfCb.apply(lambda row: (row['CbHops'] - cbHopsMin) / (cbHopsMax - cbHopsMin), axis=1) dfCb['cbDistNorm'] = dfCb.apply(lambda row: (row['CbDist'] - cbDistMin) / (cbDistMax - cbDistMin), axis=1) dfCb['cbTimeNorm'] = dfCb.apply(lambda row: (row['CbTime'] - cbTimeMin) / (cbTimeMax - cbTimeMin), axis=1) return dfCb
def calcShortestPaths_v2(G, dfRoutes, edgeWeight=None): ''' calculate shortest path between all node pairs in G, except for: - two identical nodes - two nodes within 300m of each other and not directly connected. - two nodes on the same directed route :param G: :param edgeWeight: :return: ''' shortestPaths = {} for nodei in G.nodes(): shortestPaths[nodei] = {} for nodej in G.nodes(): # IF THE 2 NODES ARE IDENTICAL if nodej==nodei: continue # IF THERE'S A DIRECT LINK BETWEEN THEM if G.has_edge(nodei, nodej): shortestPaths[nodei][nodej] = {} shortestPaths[nodei][nodej]['path'] = [nodei, nodej] shortestPaths[nodei][nodej]['len'] = calcPathLength(G, [nodei, nodej], edgeWeight) continue # IF THEY ARE ON THE SAME DIRECTED ROUTE (AND nodei IS BEFORE nodej) # combines routeID_StationDirection (e.g. 25_0) of all directed routes passing nodei and passing nodej # rNdi and rNdj are pandas Series rNdi = G.nodes[nodei][const.GNodeAttribs.routes.name].apply( lambda row: '%d_%d' % (row[const.GNodeRouteCols.RouteId.name], row[const.GNodeRouteCols.StationDirection.name]), axis=1) rNdj = G.nodes[nodej][const.GNodeAttribs.routes.name].apply( lambda row: '%d_%d' % (row[const.GNodeRouteCols.RouteId.name], row[const.GNodeRouteCols.StationDirection.name]), axis=1) # if found at least one common directed route, i.e. nodei and nodej are on the same directed route commonRoutes = list(set(rNdi.values).intersection(set(rNdj.values))) # reverse engineer to get routeID and StationDirection using the 1st value in commonRoutes # ideally we should examine all routes in commonRoutes and pick the shortest. # However picking the 1st route that have nodei before nodej should be fine 95% of the time. # Note that it is possible that we may not find any such route in commonRoutes onSameRoute = False for route in commonRoutes: routeID = int(route.split('_')[0]) stnDir = int(route.split('_')[1]) ttb = dfRoutes['designedTtb'].loc[(dfRoutes['RouteId'] == routeID) & (dfRoutes['StationDirection'] == stnDir)].values[0] idxNodei = ttb['StationCode'].index(nodei) idxNodej = ttb['StationCode'].index(nodej) if idxNodei < idxNodej: onSameRoute = True sPath = ttb['StationCode'][idxNodei:idxNodej+1] shortestPaths[nodei][nodej] = {} shortestPaths[nodei][nodej]['path'] = sPath shortestPaths[nodei][nodej]['len'] = calcPathLength(G, sPath, edgeWeight) break if onSameRoute: continue # IF 2 NODES ARE WITHIN WALK DISTANCE TO EACH OTHER AND ARE NOT ON THE SAME DIRECTED ROUTE nodeiCoord = [G.nodes[nodei][const.GNodeAttribs.Lng.name], G.nodes[nodei][const.GNodeAttribs.Lat.name]] nodejCoord = [G.nodes[nodej][const.GNodeAttribs.Lng.name], G.nodes[nodej][const.GNodeAttribs.Lat.name]] dist = utils.calcGeodesicDist(nodeiCoord, nodejCoord) # distance in metres if dist <= const.maxWalkDist: continue # NONE OF THE ABOVE sPath = nx.shortest_path(G, source=nodei, target=nodej, weight=edgeWeight, method='dijkstra') # method='bellman-ford' shortestPaths[nodei][nodej] = {} shortestPaths[nodei][nodej]['path'] = sPath shortestPaths[nodei][nodej]['len'] = calcPathLength(G, sPath, edgeWeight) return shortestPaths