3

Using ArcGIS Desktop and the Network Analyst extension, I want to determine the path of an optimized walking school bus route to school. a walking school bus is essentially a system by which adult volunteers chaperone elementary school children along a pre-set pedestrian path, to help keep them safe from traffic hazards and busy intersections. the idea would be that students would, starting from home, travel to their nearest walking bus "stop", then take the walking bus all the way to school.

I have a very detailed pedestrian network for my study area. scaled cost barriers include intersection controls, areas with high crime. the walking bus would bypass most of these barriers

Is there a workflow that could help determine the optimum location for the walking bus route itself? Right now my process is as follows:

Using closest facility analysis I determine the shortest path to the school for each house, then look at the density of routes along each segment of the network using a spatial join and the join count to find common "corridors". I would then digitize a route visually along this.

This is obviously fairly imprecise, and relies heavily on human judgement.

Is there a better way to go about this?

1 Answer 1

5

This looks like a Steiner tree problem. You'll need some programming to solve it. Picture below shows manually improved output of algorithm from networkX:

enter image description here

and I think computing "flow" in this network will bring you even closer to near optimal solution:

enter image description here

In this case SE student looks like a best candidate to start route.

What you are doing will give you blurry pattern like that:

enter image description here

The script below assumes: - you have point layer - nodes at roads ends at least 2 of them (terminals) selected - polyline layer - edges, that have from and to INDICES of nodes populated - field TIMES in polylines stores a cost of travel through that edge (length?)

Script creates undirected graph first from all nodes (each has to be reachable from others) and computes much smaller new graph where nodes are terminals only and cost of travel between them is shortest distance. After that it computes minimum spanning tree of smaller graph and traces paths between terminals of original large graph. Remember, it is only approximation of optimal Steiner tree, see Wikipedia.

Script is tailored for my work environment (up to line 45) and not very tidy, so ask if any questions.

import arcpy, traceback, os, sys
import itertools
from itertools import tee,chain,combinations
scriptsPath=os.path.dirname(os.path.realpath(__file__))
os.chdir(scriptsPath)
import COMMON
import networkx as nx
import random, numpy, copy

try:
  def showPyMessage():
    arcpy.AddMessage(str(time.ctime()) + " - " + message)
  def pairwise(iterable, cyclic=False):
      "s -> (s0, s1), (s1, s2), (s2, s3), ..."
      a, b = tee(iterable)
      first = next(b, None)
      if cyclic is True:
          return zip(a, chain(b, (first,)))
      return zip(a, b)

  ## FIND ENVIRONMENT TABLE
  mxd = arcpy.mapping.MapDocument("CURRENT")
  theT=COMMON.getTable(mxd)
  ##  FIND NODES LAYER
  theNodesLayer = COMMON.getInfoFromTable(theT,1)
  theNodesLayer = COMMON.isLayerExist(mxd,theNodesLayer)
##    GET NUMBER OF NODES AND NUMBER OF SELECTED
  aBmNodes = theNodesLayer.getSelectionSet()
  nSet=len(aBmNodes)
  if nSet<2:
    arcpy.AddWarning("Please select at least 2 nodes")
    raise SystemExit('Missing input')
  arcpy.AddMessage(aBmNodes)
  ##  GET LINKS LAYER
  theLinksLayer = COMMON.getInfoFromTable(theT,9)
  theLinksLayer = COMMON.isLayerExist(mxd,theLinksLayer)
  arcpy.SelectLayerByAttribute_management(theLinksLayer, "CLEAR_SELECTION")        
  linksFromI=COMMON.getInfoFromTable(theT,14)
  linksToI=COMMON.getInfoFromTable(theT,13)
  G=nx.Graph()
  arcpy.AddMessage("Adding links to graph")
  with arcpy.da.SearchCursor(theLinksLayer, (linksFromI,linksToI,"Times")) as cursor:
    for i,(f,t,c) in enumerate(cursor):
      G.add_edge(f,t,weight=c,no=i)
  D=nx.Graph()
  for f,t in combinations(aBmNodes, 2):
    L=nx.dijkstra_path_length(G,f,t)
    D.add_edge(f,t,weight=L)
  T=nx.minimum_spanning_tree(D)
  del D
  aList=[]
  for F,T in T.edges():
    nodes=nx.dijkstra_path(G,F,T)
    for f,t in pairwise(nodes):
      aList.append(G[f][t]['no'])
  with arcpy.da.UpdateCursor(theLinksLayer, (linksFromI,linksToI,"PART")) as cursor:
    for f,t,c in cursor:
      cursor.updateRow((f,t,0))
  theLinksLayer.setSelectionSet ("NEW",aList)
  with arcpy.da.UpdateCursor(theLinksLayer, (linksFromI,linksToI,"PART")) as cursor:
    for f,t,c in cursor:
      cursor.updateRow((f,t,1))
  arcpy.RefreshActiveView() 
except:
  message = "\n*** PYTHON ERRORS *** "; showPyMessage()
  message = "Python Traceback Info: " + traceback.format_tb(sys.exc_info()[2])[0]; showPyMessage()
  message = "Python Error Info: " +  str(sys.exc_type)+ ": " + str(sys.exc_value) + "\n"; showPyMessage()
3
  • thanks so much! I am however having a bit of trouble finding the paper that forms the source of the approximation they used - i am writing a paper myself and need to cite it. also, if you had any code you could share to speed me along i would be very grateful!. I do know python.
    – Alex
    Commented Mar 11, 2019 at 5:40
  • to be clear, do I need to structure the network such that the path to the school is isolated like that? the schools I have are surrounded by suburbs and have hundreds of nodes.
    – Alex
    Commented Mar 12, 2019 at 3:39
  • Your school can be anywhere, but when in the middle you aren't likely to find single bus route.
    – FelixIP
    Commented Mar 12, 2019 at 4:11

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.