# spaghetti.Network

class spaghetti.Network(in_data=None, vertex_sig=11, unique_arcs=True, extractgraph=True, w_components=True, weightings=False, weights_kws={}, vertex_atol=None)

  Spatially-constrained network representation and analytical functionality. Naming conventions are as follows, (1) arcs and vertices for the full network object, and (2) edges and nodes for the simplified graph-theoretic object. The term ‘link’ is used to refer to a network arc or a graph edge.

  Parameters:
    in_data{`python:str`, python:iterable, `libpysal.cg.Chain`, `geopandas.GeoDataFrame`}

      The input geographic data. Either (1) a path to a shapefile (str); (2) an iterable containing `libpysal.cg.Chain` objects; (3) a single `libpysal.cg.Chain`; or (4) a `geopandas.GeoDataFrame`.

    vertex_sig `python:int`

      Round the x and y coordinates of all vertices to `vertex_sig` significant digits (combined significant digits on the left and right of the decimal place). Default is 11. Set to `None` for no rounding.

    unique_arcs bool

      If `True` (default), keep only unique arcs (i.e., prune out any duplicated arcs). If `False` keep all segments.

    extractgraph bool

      If `True`, extract a graph-theoretic object with no degree 2 nodes. Default is `True`.

    w_components bool

      Set to `False` to not record connected components from a `libpysal.weights.W` object. Default is `True`.

    weightings{`python:dict`, bool}

      If dict, lists of weightings for each arc. If bool, `True` flags `self.arc_lengths` as the weightings, `False` sets no weightings. Default is `False`.

    weights_kws `python:dict`

      Keyword arguments for `libpysal.weights.W`. Default is `dict()`.

    vertex_atol{`python:int`, `python:None`}

      Precision for vertex absolute tolerance. Round vertex coordinates to `vertex_atol` decimal places. Default is `None`. ONLY change the default when there are known issues with digitization.

  Attributes:
    adjacencylist `python:list`

      List of lists storing vertex adjacency.

    vertex_coords `python:dict`

      Keys are vertex IDs and values are \((x,y)\) coordinates of the vertices.

    vertex_list `python:list`

      List of vertex IDs.

    vertices `python:dict`

      Keys are tuples of vertex coords and values are the vertex ID.

    arcs `python:list`

      List of arcs, where each arc is a sorted tuple of vertex IDs.

    arc_lengths `python:dict`

      Keys are tuples of sorted vertex IDs representing an arc and values are the length.

    pointpatterns `python:dict`

      Keys are a string name of the pattern and values are `PointPattern` class instances.

    distance_matrix `numpy.ndarray`

      All network vertices (non-observations) distance matrix. Distances between vertices in disparate components are recorded as `inf` by default.

    network_trees `python:dict`

      Keys are the vertex IDs (`int`). Values are dictionaries with the keys being the IDs of the destination vertex and values being lists of vertices along the shortest path. If the destination vertex is a) the origin or b) unreachable (disparate component) it is listed as itself being the neighbor.

    edges `python:list`

      Tuples of graph edge IDs.

    edge_lengths `python:dict`

      Keys are the graph edge IDs (`tuple`). Values are the graph edge length (`float`).

    non_articulation_points `python:list`

      All vertices with degree 2 that are not in an isolated island ring (loop) component.

    w_network `libpysal.weights.W`

      Weights object created from the network arcs.

    network_n_components `python:int`

      Count of connected components in the network.

    network_fully_connected bool

      `True` if the network representation is a single connected component, otherwise `False`.

    network_component_labels `numpy.ndarray`

      Component labels for network arcs.

    network_component2arc `python:dict`

      Lookup in the form {int: list} for arcs comprising network connected components keyed by component labels with arcs in a list as values.

    network_component_lengths `python:dict`

      Length of each network component (keyed by component label).

    network_longest_component `python:int`

      The ID of the longest component in the network. This is not necessarily equal to `network_largest_component`.

    network_component_vertices `python:dict`

      Lookup in the form {int: list} for vertices comprising network connected components keyed by component labels with vertices in a list as values.

    network_component_vertex_count `python:dict`

      The number of vertices in each network component (keyed by component label).

    network_largest_component `python:int`

      The ID of the largest component in the network. Within `spaghetti` the largest component is the one with the most vertices. This is not necessarily equal to `network_longest_component`.

    network_component_is_ring `python:dict`

      Lookup in the form {int: bool} keyed by component labels with values as `True` if the component is a closed ring, otherwise `False`.

    w_graph `libpysal.weights.W`

      Weights object created from the graph edges.

    graph_n_components `python:int`

      Count of connected components in the network.

    graph_fully_connected bool

      `True` if the graph representation is a single connected component, otherwise `False`.

    graph_component_labels `numpy.ndarray`

      Component labels for graph edges.

    graph_component2edge `python:dict`

      Lookup in the form {int: list} for edges comprising graph connected components keyed by component labels with edges in a list as values.

    graph_component_lengths `python:dict`

      Length of each graph component (keyed by component label).

    graph_longest_component `python:int`

      The ID of the longest component in the graph. This is not necessarily equal to `graph_largest_component`.

    graph_component_vertices `python:dict`

      Lookup in the form {int: list} for vertices comprising graph connected components keyed by component labels with vertices in a list as values.

    graph_component_vertex_count `python:dict`

      The number of vertices in each graph component (keyed by component label).

    graph_largest_component `python:int`

      The ID of the largest component in the graph. Within `spaghetti` the largest component is the one with the most vertices. This is not necessarily equal to `graph_longest_component`.

    graph_component_is_ring `python:dict`

      Lookup in the form {int: bool} keyed by component labels with values as `True` if the component is a closed ring, otherwise `False`.

  Notes

  Important: The core procedure for generating network representations is performed within the `_extractnetwork()` method. Here it is important to note that a `spaghetti.Network` instance is built up from the individual, constituent euclidean units of each line segment object. Therefore, the resulting network structure will generally have (1) more vertices and links than may expected, and, (2) many degree-2 vertices, which differs from a truly graph-theoretic object. This is demonstrated in the Caveats Tutorial.

  See [CH81], [TF83], [AMO93], [LPT95], [KRUT09], [Bar11], [Das13], [OS12d], [DB14], [Web16], for more in-depth discussion on spatial networks, graph theory, and location along networks. For related network-centric software see Snkit [RK19], SANET [OOS06], NetworkX [HSS08], Pandana [FWL12], and OSMnx [Boe17].

  Examples

  Create an instance of a network.

      >>> import spaghetti
      >>> from libpysal import examples
      >>> streets_file = examples.get_path("streets.shp")
      >>> ntw = spaghetti.Network(in_data=streets_file)

  Fetch the number connected components in the network.

      >>> ntw.network_n_components
      1

  Unique component labels in the network.

      >>> import numpy
      >>> list(numpy.unique(ntw.network_component_labels))
      [np.int32(0)]

  Show whether each component of the network is an isolated ring (or not).

      >>> ntw.network_component_is_ring
      {np.int32(0): False}

  Show how many network arcs are associated with the component.

      >>> arcs = len(ntw.network_component2arc[ntw.network_component_labels[0]])
      >>> arcs
      303

  Do the same as above, but for the graph-theoretic representation of the network object.

      >>> ntw.graph_n_components
      1
      >>> list(numpy.unique(ntw.graph_component_labels))
      [np.int32(0)]
      >>> ntw.graph_component_is_ring
      {np.int32(0): False}
      >>> edges = len(ntw.graph_component2edge[ntw.graph_component_labels[0]])
      >>> edges
      179

  The number of arcs in the network is always greater than or equal to the number of edges in the graph-theoretic representation.

      >>> arcs >= edges
      True

  Snap point observations to the network with attribute information.

      >>> crimes_file = examples.get_path("crimes.shp")
      >>> ntw.snapobservations(crimes_file, "crimes", attribute=True)

  And without attribute information.

      >>> schools_file = examples.get_path("schools.shp")
      >>> ntw.snapobservations(schools_file, "schools", attribute=False)

  Show the point patterns associated with the network.

      >>> ntw.pointpatterns.keys()
      dict_keys(['crimes', 'schools'])

  __init__(in_data=None, vertex_sig=11, unique_arcs=True, extractgraph=True, w_components=True, weightings=False, weights_kws={}, vertex_atol=None)

  Methods

  `GlobalAutoK`(pointpattern[, nsteps, ...]) | Compute a global auto \(K\)-function based on a network constrained cost matrix through Monte Carlo simulation according to the formulation adapted from [OU10].
  `Moran`(pp_name[, permutations, graph]) | Calculate a Moran's I statistic on a set of observations based on network arcs.
  `__init__`([in_data, vertex_sig, unique_arcs, ...]) |
  `allneighbordistances`(sourcepattern[, ...]) | Compute either all distances between \(i\) and \(j\) in a single point pattern or all distances between each \(i\) from a source pattern and all \(j\) from a destination pattern.
  `compute_distance_to_vertices`(x, y, arc) | Given an observation on a network arc, return the distance to the two vertices that bound that end.
  `compute_snap_dist`(pattern, idx) | Given an observation snapped to a network arc, calculate the distance from the original location to the snapped location.
  `contiguityweights`([graph, weightings, ...]) | Create a contiguity-based `libpysal.weights.W` object.
  `count_per_link`(obs_on[, graph]) | Compute the counts per arc or edge (link).
  `distancebandweights`(threshold[, ...]) | Create distance-based weights.
  `enum_links_vertex`(v0) | Returns the arcs (links) adjacent to vertices.
  `extractgraph`() | Using the existing network representation, create a graph-theoretic representation by removing all vertices with a neighbor incidence of two (non-articulation points).
  `full_distance_matrix`(n_processes[, gen_tree]) | All vertex-to-vertex distances on a network.
  `identify_components`(w[, graph]) | Identify connected component information from a `libpysal.weights.W` object
  `loadnetwork`(filename) | Load a network from a binary file saved on disk.
  `nearestneighbordistances`(sourcepattern[, ...]) | Compute the interpattern nearest neighbor distances or the intrapattern nearest neighbor distances between a source pattern and a destination pattern.
  `savenetwork`(filename) | Save a network to disk as a binary file.
  `shortest_paths`(tree, pp_orig[, pp_dest]) | Return the shortest paths between observation points as `libpysal.cg.Chain` objects.
  `simulate_observations`(count[, distribution]) | Generate a simulated point pattern on the network.
  `snapobservations`(in_data, name[, ...]) | Snap a point pattern shapefile to a network object.
  `split_arcs`(split_param[, split_by, ...]) | Split all network arcs at either a fixed distance or fixed count.

  GlobalAutoK(pointpattern, nsteps=10, permutations=99, threshold=0.5, distribution='uniform', upperbound=None)

    Compute a global auto \(K\)-function based on a network constrained cost matrix through Monte Carlo simulation according to the formulation adapted from [OU10]. See the Notes section for further description.

    Parameters:
      pointpattern `spaghetti.PointPattern`

        A `spaghetti` point pattern object.

      nsteps `python:int`

        The number of steps at which the count of the nearest neighbors is computed. Default is `10`.

      permutations `python:int`

        The number of permutations to perform. Default is `99`.

      threshold `python:float`

        The level at which significance is computed. (0.5 would be 97.5% and 2.5%). Default is `0.5`.

      distribution `python:str`

        The distribution from which random points are sampled. Currently, the only supported distribution is `'uniform'`.

      upperbound `python:float`

        The upper bound at which the \(K\)-function is computed. Defaults to the maximum observed nearest neighbor distance.

    Returns:
      GlobalAutoK `spaghetti.analysis.GlobalAutoK`

        The global auto \(K\)-function class instance.

    See also

    `pointpats.K`

    Notes

    The \(K\)-function can be formulated as:

    \[\displaystyle K(r)=\frac{\sum^n_{i=1} \#[\hat{A} \in D(a_i, r)]}{n\lambda},\]

    where $n$ is the set cardinality of \(A\), \(\hat{A}\) is the subset of observations in \(A\) that are within \(D\) units of distance from \(a_i\) (each single observation in \(A\)), and \(r\) is the range of distance values over which the \(K\)-function is calculated. The \(\lambda\) term is the intensity of observations along the network, calculated as:

    \[\displaystyle \lambda = \frac{n}{\big|N_{arcs}\big|},\]

    where \(\big|N_{arcs}\big|\) is the summed length of network arcs. The global auto \(K\)-function measures overall clustering in one set of observations by comparing all intra-set distances over a range of distance buffers \(D \in r\). The \(K\)-function improves upon nearest-neighbor distance measures through the analysis of all neighbor distances. For an explanation on how to interpret the results of the \(K\)-function see the Network Spatial Dependence tutorial here.

    For original implementation see [Rip76] and [Rip77]. For further Network-K formulations see [OY01], [OS12b], and [BNR+20].

    Examples

    Create a network instance.

        >>> import spaghetti
        >>> from libpysal import examples
        >>> ntw = spaghetti.Network(in_data=examples.get_path("streets.shp"))

    Snap observation points onto the network.

        >>> pt_str = "schools"
        >>> in_data = examples.get_path(pt_str+".shp")
        >>> ntw.snapobservations(in_data, pt_str, attribute=True)
        >>> schools = ntw.pointpatterns[pt_str]

    Compute a \(K\)-function from school observations with `99` `permutations` at `10` intervals.

        >>> kres = ntw.GlobalAutoK(schools, permutations=99, nsteps=10)
        >>> kres.lowerenvelope.shape[0]
        10

  Moran(pp_name, permutations=999, graph=False)

    Calculate a Moran’s I statistic on a set of observations based on network arcs. The Moran’s I test statistic allows for the inference of how clustered (or dispersed) a dataset is while considering both attribute values and spatial relationships. A value of closer to +1 indicates absolute clustering while a value of closer to -1 indicates absolute dispersion. Complete spatial randomness takes the value of 0. See the `esda` documentation for in-depth descriptions and tutorials.

    Parameters:
      pp_name `python:str`

        The name of the point pattern in question.

      permutations `python:int`

        The number of permutations to perform. Default is `999`.

      graph bool

        Perform the Moran calculation on the graph W object (`True`). Default is `False`, which performs the Moran calculation on the network W object.

    Returns:
      moran `esda.Moran`

        A Moran’s I statistic object results.

      y `python:list`

        The y-axis (counts).

    Notes

    See [CO81] and [RWK+19] for more details.

    Examples

    Create a network instance.

        >>> import spaghetti
        >>> from libpysal import examples
        >>> ntw = spaghetti.Network(in_data=examples.get_path("streets.shp"))

    Snap observation points onto the network.

        >>> crimes = "crimes"
        >>> in_data = examples.get_path(crimes+".shp")
        >>> ntw.snapobservations(in_data, crimes, attribute=True)

    Compute a Moran’s \(I\) from crime observations.

        >>> moran_res, _ = ntw.Moran(crimes)
        >>> round(moran_res.I, 6)
        np.float64(0.005193)

  allneighbordistances(sourcepattern, destpattern=None, fill_diagonal=None, n_processes=1, gen_tree=False, snap_dist=False)

    Compute either all distances between \(i\) and \(j\) in a single point pattern or all distances between each \(i\) from a source pattern and all \(j\) from a destination pattern.

    Parameters:
      sourcepattern{`python:str`, `spaghetti.PointPattern`}

        The key of a point pattern snapped to the network or the full `spaghetti.PointPattern` object.

      destpattern `python:str`

        (Optional) The key of a point pattern snapped to the network or the full `spaghetti.PointPattern` object.

      fill_diagonal{`python:float`, `python:int`}

        (Optional) Fill the diagonal of the cost matrix. Default is `None` and will populate the diagonal with `numpy.nan`. Do not declare a `destpattern` for a custom `fill_diagonal`.

      n_processes{`python:int`, `python:str`}

        Specify the number of cores to utilize. Default is 1 core. Use `"all"` to request all available cores. Specify the exact number of cores with an integer.

      gen_tree bool

        Rebuild shortest path `True`, or skip `False`. Default is `False`.

      snap_dist bool

        Flag as `True` to include the distance from the original location to the snapped location along the network. Default is `False`.

    Returns:
      nearest `numpy.ndarray`

        An array of shape (n,m) storing distances between all source and destination points.

      tree_nearest `python:dict`

        Nearest network node to point pattern vertex shortest path lookup. The values of the dictionary are a tuple of the nearest source vertex and the nearest destination vertex to query the lookup tree. If two observations are snapped to the same network arc a flag of -.1 is set for both the source and destination network vertex indicating the same arc is used while also raising an `IndexError` when rebuilding the path.

    Examples

    Create a network instance.

        >>> import spaghetti
        >>> from libpysal import examples
        >>> import numpy
        >>> ntw = spaghetti.Network(examples.get_path("streets.shp"))

    Snap observations to the network.

        >>> ntw.snapobservations(
        ...     examples.get_path("crimes.shp"), "crimes", attribute=True
        ... )

    Calculate all distances between observations in the `crimes` dataset.

        >>> s2s_dist = ntw.allneighbordistances("crimes")

    If calculating a `type-a` to `type-a` distance matrix the distance between an observation and itself is `nan` and the distance between one observation and another will be positive value.

        >>> s2s_dist[0,0], s2s_dist[1,0]
        (np.float64(nan), np.float64(3105.189475447081))

    If calculating a `type-a` to `type-b` distance matrix the distance between all observations will likely be positive values, may be zero (or approximately zero), but will never be negative.

        >>> ntw.snapobservations(
        ...     examples.get_path("schools.shp"), "schools", attribute=False
        ... )
        >>> s2d_dist = ntw.allneighbordistances("crimes", destpattern="schools")
        >>> numpy.round((s2d_dist[0,0], s2d_dist[1,0]), 5)
        array([4520.72354, 6340.42297])

    Shortest paths can also be reconstructed when desired by setting the `gen_tree` keyword argument to `True`. Here it is shown that the shortest path between school `6` and school `7` flows along network arcs through network vertices `173` and `64`. The `ntw.network_trees` attribute may then be queried for the network elements comprising that path.

        >>> d2d_dist, tree = ntw.allneighbordistances("schools", gen_tree=True)
        >>> tree[(6, 7)]
        (173, 64)

  compute_distance_to_vertices(x, y, arc)

    Given an observation on a network arc, return the distance to the two vertices that bound that end.

    Parameters:
      x `python:float`

        The x-coordinate of the snapped point.

      y `python:float`

        The y-coordinate of the snapped point.

      arc `python:tuple`

        The (vtx0, vtx1) representation of the network arc.

    Returns:
      d1 `python:float`

        The distance to vtx0. Always the vertex with the lesser ID.

      d2 `python:float`

        The distance to vtx1. Always the vertex with the greater ID.

  compute_snap_dist(pattern, idx)

    Given an observation snapped to a network arc, calculate the distance from the original location to the snapped location.

    Parameters:
      pattern `spaghetti.PointPattern`

        The point pattern object.

      idx `python:int`

        The point ID.

    Returns:
      dist `python:float`

        The euclidean distance from original location to the snapped location.

  contiguityweights(graph=True, weightings=None, from_split=False, weights_kws={})

    Create a contiguity-based `libpysal.weights.W` object.

    Parameters:
      graph bool

        Controls whether the `libpysal.weights.W` is generated using the spatial representation (`False`) or the graph representation (`True`). Default is `True`.

      weightings{`python:dict`, `python:None`}

        Dictionary of lists of weightings for each arc/edge. Default is `None`.

      from_split bool

        Flag for whether the method is being called from within `split_arcs()` (`True`) or not (`False`). Default is `False`.

      weights_kws `python:dict`

        Keyword arguments for `libpysal.weights.W`. Default is `dict()`.

    Returns:
      W `libpysal.weights.W`

        A `W` representing the binary adjacency of the network.

    See also

    `libpysal.weights.W`

    Notes

    See [RA07] for more details.

    Examples

    Instantiate a network.

        >>> import spaghetti
        >>> from libpysal import examples
        >>> import numpy
        >>> ntw = spaghetti.Network(examples.get_path("streets.shp"))

    Snap point observations to the network with attribute information.

        >>> ntw.snapobservations(
        ...     examples.get_path("crimes.shp"), "crimes", attribute=True
        ... )

    Find counts per network arc.

        >>> counts = ntw.count_per_link(
        ...     ntw.pointpatterns["crimes"].obs_to_arc, graph=False
        ... )
        >>> counts[(50, 165)]
        4

    Create a contiguity-based `W` object.

        >>> w = ntw.contiguityweights(graph=False)
        >>> w.n, w.n_components
        (303, 1)

  count_per_link(obs_on, graph=False)

    Compute the counts per arc or edge (link).

    Parameters:
      obs_on `python:dict`

        Dictionary of observations on the network. Either in the form `{(<LINK>):{<POINT_ID>:(<COORDS>)}}` or `{<LINK>:[(<COORD>),(<COORD>)]}`.

      graph bool

        Count observations on graph edges (`True`) or network arcs (`False`). Default is `False`.

    Returns:
      counts `python:dict`

        Counts per network link in the form `{(<LINK>):<COUNT>}`.

    Examples

    Note that this passes the `obs_to_arc` or `obs_to_edge` attribute of a point pattern snapped to the network.

        >>> import spaghetti
        >>> from libpysal import examples
        >>> ntw = spaghetti.Network(examples.get_path("streets.shp"))

    Snap observations to the network.

        >>> ntw.snapobservations(
        ...     examples.get_path("crimes.shp"), "crimes", attribute=True
        ... )

        >>> counts = ntw.count_per_link(
        ...     ntw.pointpatterns["crimes"].obs_to_arc, graph=False
        ... )
        >>> counts[(140, 142)]
        10

        >>> s = sum([v for v in list(counts.values())])
        >>> s
        287

  distancebandweights(threshold, n_processes=1, gen_tree=False, weights_kws={})

    Create distance-based weights.

    Parameters:
      threshold `python:float`

        Distance threshold value.

      n_processes{`python:int`, `python:str`}

        Specify the number of cores to utilize. Default is 1 core. Use `"all"` to request all available cores. Specify the exact number of cores with an integer.

      gen_tree bool

        Rebuild shortest path with `True`, or skip with `False`. Default is `False`.

      weights_kws `python:dict`

        Keyword arguments for `libpysal.weights.W`. Default is `dict()`.

    Returns:
      w `libpysal.weights.W`

        A `W` object representing the binary adjacency of the network.

    See also

    `libpysal.weights.W`

    Notes

    See [AR14] and [RAL+15] for more details regarding spatial weights.

    Examples

    Instantiate an instance of a network.

        >>> import spaghetti
        >>> from libpysal import examples
        >>> import warnings
        >>> streets_file = examples.get_path("streets.shp")
        >>> ntw = spaghetti.Network(in_data=streets_file)

    Create a contiguity-based `W` object based on network distance, `500` US feet in this case.

        >>> w = ntw.distancebandweights(
        ...     threshold=500, weights_kws=dict(silence_warnings=True)
        ... )

    Show the number of units in the `W` object.

        >>> w.n
        230

    There are 7 components in the `W` object.

        >>> w.n_components
        7

    There are `8` units with `3` neighbors in the `W` object.

        >>> w.histogram[-1]
        (np.int64(8), np.int64(3))

  enum_links_vertex(v0)

    Returns the arcs (links) adjacent to vertices.

    Parameters:
      v0 `python:int`

        The vertex ID.

    Returns:
      links `python:list`

        List of tuple arcs adjacent to the vertex.

    Examples

    Create an instance of a network.

        >>> import spaghetti
        >>> from libpysal import examples
        >>> ntw = spaghetti.Network(examples.get_path("streets.shp"))

    Enumerate the links/arcs that are adjacent to vertex `24`.

        >>> ntw.enum_links_vertex(24)
        [(24, 48), (24, 25), (24, 26)]

  extractgraph()

    Using the existing network representation, create a graph-theoretic representation by removing all vertices with a neighbor incidence of two (non-articulation points). That is, we assume these vertices are bridges between vertices with higher or lower incidence.

  full_distance_matrix(n_processes, gen_tree=False)

    All vertex-to-vertex distances on a network. This method is called from within `allneighbordistances()`, `nearestneighbordistances()`, and `distancebandweights()`.

    Parameters:
      n_processes `python:int`

        Specify the number of cores to utilize. Default is 1 core. Use `"all"` to request all available cores. Specify the exact number of cores with an integer.

      gen_tree bool

        Rebuild shortest path `True`, or skip `False`. Default is `False`.

    Notes

    Based on [Dij59] and [OS12a].

  identify_components(w, graph=False)

    Identify connected component information from a `libpysal.weights.W` object

    Parameters:
      w `libpysal.weights.W`

        Weights object created from the network segments (either raw or graph-theoretic).

      graph bool

        Flag for a raw network (`False`) or graph-theoretic network (`True`). Default is `False`.

  static loadnetwork(filename)

    Load a network from a binary file saved on disk.

    Parameters:
      filename `python:str`

        The filename where the network is saved.

    Returns:
      self `spaghetti.Network`

        A pre-computed `spaghetti` network object.

  nearestneighbordistances(sourcepattern, destpattern=None, n_processes=1, gen_tree=False, all_dists=None, snap_dist=False, keep_zero_dist=True)

    Compute the interpattern nearest neighbor distances or the intrapattern nearest neighbor distances between a source pattern and a destination pattern.

    Parameters:
      sourcepattern `python:str`

        The key of a point pattern snapped to the network.

      destpattern `python:str`

        (Optional) The key of a point pattern snapped to the network.

      n_processes{`python:int`, `python:str`}

        Specify the number of cores to utilize. Default is 1 core. Use `"all"` to request all available cores. Specify the exact number of cores with an integer.

      gen_tree bool

        Rebuild shortest path `True`, or skip `False`. Default is `False`.

      all_dists `numpy.ndarray`

        An array of shape \((n,n)\) storing distances between all points.

      snap_dist bool

        Flag as `True` to include the distance from the original location to the snapped location along the network. Default is `False`.

      keep_zero_dist bool

        Include zero values in minimum distance `True` or exclude `False`. Default is `True`. If the source pattern is the same as the destination pattern the diagonal is filled with `numpy.nan`.

    Returns:
      nearest `python:dict`

        Nearest neighbor distances keyed by the source point ID with the value as as tuple of lists containing nearest destination point ID(s) and distance.

    Examples

    Instantiate a network.

        >>> import spaghetti
        >>> from libpysal import examples
        >>> ntw = spaghetti.Network(examples.get_path("streets.shp"))

    Snap observations to the network.

        >>> ntw.snapobservations(examples.get_path("crimes.shp"), "crimes")

    Fetch nearest neighbor distances while (potentially) keeping neighbors that have been geocoded directly on top of each other. Here it is demonstrated that observation `11` has two neighbors (`18` and `19`) at an exactly equal distance. However, observation `18` is shown to have only one neighbor (`18`) with no distance between them.

        >>> nn = ntw.nearestneighbordistances("crimes", keep_zero_dist=True)
        >>> nn[11], nn[18]
        (([18, 19], np.float64(165.33982412719126)), ([19], np.float64(0.0)))

    This may be remedied by setting the `keep_zero_dist` keyword argument to `False`. With this parameter set, observation `11` still has the same neighbor/distance values, but observation `18` now has a single nearest neighbor (`11`) with a non-zero, postive distance.

        >>> nn = ntw.nearestneighbordistances("crimes", keep_zero_dist=False)
        >>> nn[11], nn[18]
        (([18, 19], np.float64(165.33982412719126)), ([11], np.float64(165.33982412719126)))

    There are valid reasons for both retaining or masking zero distance neighbors. When conducting analysis, thought must be given as to which model more accurately represents the specific scenario.

  savenetwork(filename)

    Save a network to disk as a binary file.

    Parameters:
      filename `python:str`

        The filename where the network should be saved. This should be a full path or it will be saved in the current directory.

    Examples

    Create a network instance.

        >>> import spaghetti
        >>> from libpysal import examples
        >>> ntw = spaghetti.Network(examples.get_path("streets.shp"))

    Save out the network instance.

        >>> ntw.savenetwork("mynetwork.pkl")

  shortest_paths(tree, pp_orig, pp_dest=None)

    Return the shortest paths between observation points as `libpysal.cg.Chain` objects.

    Parameters:
      tree `python:dict`

        See `tree_nearest` in `spaghetti.Network.allneighbordistances()`.

      pp_orig `python:str`

        Origin point pattern for shortest paths. See `name` in `spaghetti.Network.snapobservations()`.

      pp_dest `python:str`

        Destination point pattern for shortest paths. See `name` in `spaghetti.Network.snapobservations()`. Defaults `pp_orig` if not declared.

    Returns:
      paths `python:list`

        The shortest paths between observations as geometric objects. Each element of the list is a list where the first element is an origin-destination pair tuple and the second element is a `libpysal.cg.Chain`.

    Raises:
      `AttributeError`

        This exception is raised when an attempt to extract shortest path geometries is being made that but the `network_trees` attribute does not exist within the network object.

    Examples

    Instantiate a network.

        >>> import spaghetti
        >>> from libpysal import examples
        >>> ntw = spaghetti.Network(examples.get_path("streets.shp"))

    Snap observations to the network.

        >>> ntw.snapobservations(examples.get_path("schools.shp"), "schools")

    Create shortest path trees between observations.

        >>> _, tree = ntw.allneighbordistances("schools", gen_tree=True)

    Generate geometric objects from trees.

        >>> paths = ntw.shortest_paths(tree, "schools")

    Extract the first path, which is between observations `0` and `1`.

        >>> path = paths[0]
        >>> path[0]
        (0, 1)

    The are `n` vertices in the path between observations `0` and `1`.

        >>> n = len(path[1].vertices)
        >>> n
        10

  simulate_observations(count, distribution='uniform')

    Generate a simulated point pattern on the network.

    Parameters:
      count `python:int`

        The number of points to create.

      distribution `python:str`

        A distribution of random points. Currently, the only supported distribution is uniform.

    Returns:
      random_pts `python:dict`

        Keys are the edge tuple. Values are lists of new point coordinates.

    See also

    `numpy.random.Generator.uniform`

    Examples

    Instantiate a network.

        >>> import spaghetti
        >>> from libpysal import examples
        >>> ntw = spaghetti.Network(examples.get_path("streets.shp"))

    Snap observations to the network.

        >>> ntw.snapobservations(
        ...     examples.get_path("crimes.shp"), "crimes", attribute=True
        ... )

    Isolate the number of points in the dataset.

        >>> npts = ntw.pointpatterns["crimes"].npoints
        >>> npts
        287

    Simulate `npts` number of points along the network in a uniform distribution.

        >>> sim = ntw.simulate_observations(npts)
        >>> isinstance(sim, spaghetti.network.SimulatedPointPattern)
        True
        >>> sim.npoints
        287

  snapobservations(in_data, name, idvariable=None, attribute=False)

    Snap a point pattern shapefile to a network object. The point pattern is stored in the `network.pointpattern` attribute of the network object.

    Parameters:
      in_data{`geopandas.GeoDataFrame`, `python:str`}

        The input geographic data. Either (1) a path to a shapefile (str); or (2) a `geopandas.GeoDataFrame`.

      name `python:str`

        Name to be assigned to the point dataset.

      idvariable `python:str`

        Column name to be used as the ID variable.

      attribute bool

        Defines whether attributes should be extracted. `True` for attribute extraction. `False` for no attribute extraction. Default is `False`.

    Notes

    See [GFH20] for a detailed discussion on the modeling consequences of snapping points to spatial networks.

    Examples

    Instantiate a network.

        >>> import spaghetti
        >>> from libpysal import examples
        >>> streets_file = examples.get_path("streets.shp")
        >>> ntw = spaghetti.Network(in_data=streets_file)

    Snap observations to the network.

        >>> pt_str = "crimes"
        >>> in_data = examples.get_path(pt_str+".shp")
        >>> ntw.snapobservations(in_data, pt_str, attribute=True)

    Isolate the number of points in the dataset.

        >>> ntw.pointpatterns[pt_str].npoints
        287

  split_arcs(split_param, split_by='distance', w_components=True, weights_kws={})

    Split all network arcs at either a fixed distance or fixed count.

    Parameters:
      split_param{`python:int`, `python:float`}

        Either the number of desired resultant split arcs or the distance at which arcs are split.

      split_by `python:str`

        Either `'distance'` or `'count'`. Default is `'distance'`.

      w_components bool

        Set to `False` to not record connected components from a `libpysal.weights.W` object. Default is `True`.

      weights_kws `python:dict`

        Keyword arguments for `libpysal.weights.W`. Default is `dict()`.

    Returns:
      split_network `spaghetti.Network`

        A newly instantiated `spaghetti.Network` object.

    Examples

    Instantiate a network.

        >>> import spaghetti
        >>> from libpysal import examples
        >>> ntw = spaghetti.Network(examples.get_path("streets.shp"))

    Split the network into a segments of 200 distance units in length (US feet in this case). This will include “remainder” segments unless the network is comprised of arcs with lengths exactly divisible by `distance`.

        >>> n200 = ntw.split_arcs(200.0)
        >>> len(n200.arcs)
        688

    The number of arcs within the new object can be accessed via the weights object, as well. These counts will be equal.

        >>> len(n200.arcs) == n200.w_network.n
        True

    Neighboring arcs can also be queried through the weight object.

        >>> n200.w_network.neighbors[72,392]
        [(71, 72), (72, 252), (72, 391), (392, 393)]

    Network arcs can also be split by a specified number of divisions with the `split_by` keyword set to `'count'`, which is `'distance'` by default. For example, each arc can be split into 2 equal parts.

        >>> n2 = ntw.split_arcs(2, split_by="count")
        >>> len(n2.arcs)
        606