docs: def truncate_graph_bbox(G, north, south, east, west, truncate_by_edge=False, retain_all=False):
      """
      Remove every node in graph that falls outside a bounding box.
  
      Needed because overpass returns entire ways that also include nodes outside
      the bbox if the way (that is, a way with a single OSM ID) has a node inside
      the bbox at some point.
  
      Parameters
      ----------
      G : networkx multidigraph
      north : float
          northern latitude of bounding box
      south : float
          southern latitude of bounding box
      east : float
          eastern longitude of bounding box
      west : float
          western longitude of bounding box
      truncate_by_edge : bool
          if True retain node if it's outside bbox but at least one of node's
          neighbors are within bbox
      retain_all : bool
          if True, return the entire graph even if it is not connected
  
      Returns
      -------
      networkx multidigraph
      """
  
      start_time = time.time()
      G = G.copy()
      nodes_outside_bbox = []
  
      for node, data in G.nodes(data=True):
          if data['y'] > north or data['y'] < south or data['x'] > east or data['x'] < west:
              # this node is outside the bounding box
              if not truncate_by_edge:
                  # if we're not truncating by edge, add node to list of nodes
                  # outside the bounding box
                  nodes_outside_bbox.append(node)
              else:
                  # if we're truncating by edge, see if any of node's neighbors
                  # are within bounding box
                  any_neighbors_in_bbox = False
                  neighbors = list(G.successors(node)) + list(G.predecessors(node))
                  for neighbor in neighbors:
                      x = G.nodes[neighbor]['x']
                      y = G.nodes[neighbor]['y']
                      if y < north and y > south and x < east and x > west:
                          any_neighbors_in_bbox = True
                          break
  
                  # if none of its neighbors are within the bounding box, add node
                  # to list of nodes outside the bounding box
                  if not any_neighbors_in_bbox:
                      nodes_outside_bbox.append(node)
  
      G.remove_nodes_from(nodes_outside_bbox)
      log('Truncated graph by bounding box in {:,.2f} seconds'.format(time.time()-start_time))
  
      # remove any isolated nodes and retain only the largest component (if
      # retain_all is True)
      if not retain_all:
          G = remove_isolated_nodes(G)
          G = get_largest_component(G)
  
      return G