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)[source]

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{str, list, tuple, numpy.ndarray, 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_sigint

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_arcsbool

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

extractgraphbool

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

w_componentsbool

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

weightings{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_kwsdict

Keyword arguments for libpysal.weights.W.

vertex_atol{int, 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.

Notes

See [CH81], [TF83], [AMO93], [LabbePT95], [KRUT09], [Barthelemy11], [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))
[0]

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

>>> ntw.network_component_is_ring
{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))
[0]
>>> ntw.graph_component_is_ring
{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'])
Attributes
adjacencylistlist

List of lists storing vertex adjacency.

vertex_coordsdict

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

vertex_listlist

List of vertex IDs.

verticesdict

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

arcslist

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

arc_lengthsdict

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

pointpatternsdict

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

distance_matrixnumpy.ndarray

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

network_treesdict

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.

edgeslist

Tuples of graph edge IDs.

edge_lengthsdict

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

non_articulation_pointslist

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

w_networklibpysal.weights.W

Weights object created from the network arcs.

network_n_componentsint

Count of connected components in the network.

network_fully_connectedbool

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

network_component_labelsnumpy.ndarray

Component labels for network arcs.

network_component2arcdict

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_lengthsdict

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

network_longest_componentint

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

network_component_verticesdict

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_countdict

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

network_largest_componentint

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_ringdict

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

w_graphlibpysal.weights.W

Weights object created from the graph edges.

graph_n_componentsint

Count of connected components in the network.

graph_fully_connectedbool

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

graph_component_labelsnumpy.ndarray

Component labels for graph edges.

graph_component2edgedict

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_lengthsdict

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

graph_longest_componentint

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

graph_component_verticesdict

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_countdict

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

graph_largest_componentint

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_ringdict

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

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

Initialize self. See help(type(self)) for accurate signature.

Methods

NetworkF(self, pointpattern[, nsteps, …])

Compute a network constrained F-function, which is a cumulative frequency distribution of random distances within a set of observations associated with a network.

NetworkG(self, pointpattern[, nsteps, …])

Compute a network constrained G-function, which is a cumulative frequency distribution of nearest neighbor distances within a set of observations associated with a network.

NetworkK(self, pointpattern[, nsteps, …])

Compute a network constrained K-function.

__init__(self[, in_data, vertex_sig, …])

Initialize self.

allneighbordistances(self, 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(self, x, y, arc)

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

compute_snap_dist(self, pattern, idx)

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

contiguityweights(self[, graph, weightings, …])

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

count_per_link(self, obs_on[, graph])

Compute the counts per arc or edge (link).

distancebandweights(self, threshold[, …])

Create distance-based weights.

enum_links_vertex(self, v0)

Returns the arcs (links) adjacent to vertices.

extractgraph(self)

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(self, n_processes[, …])

All vertex-to-vertex distances on a network.

identify_components(self, 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(self, sourcepattern)

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

savenetwork(self, filename)

Save a network to disk as a binary file.

shortest_paths(self, tree, pp_orig[, …])

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

simulate_observations(self, count[, …])

Generate a simulated point pattern on the network.

snapobservations(self, in_data, name[, …])

Snap a point pattern shapefile to a network object.

split_arcs(self, distance)

Split all of the arcs in the network at a fixed distance.

NetworkF(self, pointpattern, nsteps=10, permutations=99, threshold=0.2, distribution='uniform', lowerbound=None, upperbound=None)[source]

Compute a network constrained F-function, which is a cumulative frequency distribution of random distances within a set of observations associated with a network.

Parameters
pointpatternspaghetti.PointPattern

A spaghetti point pattern object.

nstepsint

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

permutationsint

The number of permutations to perform. Default 99.

thresholdfloat

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

distributionstr

The distribution from which random points are sampled. Either "uniform" or "poisson".

lowerboundfloat

The lower bound at which the F-function is computed. Default 0.

upperboundfloat

The upper bound at which the F-function is computed. Defaults to the maximum observed nearest neighbor distance.

Returns
NetworkFspaghetti.analysis.NetworkF

A network F class instance.

Notes

This is a network-constrained version based on the Euclidean formulation found in [OSullivanU10] and mentioned in [OS12c]. It is formulated in [OSullivanU10] as:

\[F(d) = \frac{\#[d_{min}(p_i, S)<d]}{m}\]

where $p_i$ are randomly selected observations totaling $m$ in $S$ and $d$ is each step of distance along the network.

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)

Simulate observations along the network.

>>> schools = ntw.pointpatterns[pt_str]
>>> sim = ntw.simulate_observations(schools.npoints)

Compute a network constrained F-function of schools with 5 permutations and 10 nsteps.

>>> fres = ntw.NetworkF(schools, permutations=5, nsteps=10)
>>> fres.lowerenvelope.shape[0]
10
NetworkG(self, pointpattern, nsteps=10, permutations=99, threshold=0.5, distribution='uniform', lowerbound=None, upperbound=None)[source]

Compute a network constrained G-function, which is a cumulative frequency distribution of nearest neighbor distances within a set of observations associated with a network.

Parameters
pointpatternspaghetti.PointPattern

A spaghetti point pattern object.

nstepsint

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

permutationsint

The number of permutations to perform. Default 99.

thresholdfloat

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

distributionstr

The distribution from which random points are sampled Either "uniform" or "poisson".

lowerboundfloat

The lower bound at which the G-function is computed. Default 0.

upperboundfloat

The upper bound at which the G-function is computed. Defaults to the maximum observed nearest neighbor distance.

Returns
NetworkGspaghetti.analysis.NetworkG

A network G class instance.

Notes

This is a network-constrained version based on the Euclidean formulation found in [OSullivanU10] and mentioned in [OS12c]. It is formulated in [OSullivanU10] as:

\[G(d) = \frac{\#(d_{min}(s_i)<d)}{n}\]

where $s_i$ are observations totaling $n$ in $S$ and $d$ is each step of distance along the network.

[note from `jlaura`] Both the G and K functions generate a full distance matrix. This is because, I know that the full generation is correct and I believe that the truncated generated, e.g. nearest neighbor, has a bug.

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)

Simulate observations along the network.

>>> schools = ntw.pointpatterns[pt_str]
>>> sim = ntw.simulate_observations(schools.npoints)

Compute a network constrained G-function of schools with 5 permutations and 10 nsteps.

>>> gres = ntw.NetworkG(schools, permutations=5, nsteps=10)
>>> gres.lowerenvelope.shape[0]
10
NetworkK(self, pointpattern, nsteps=10, permutations=99, threshold=0.5, distribution='uniform', lowerbound=None, upperbound=None)[source]

Compute a network constrained K-function.

Parameters
pointpatternspaghetti.PointPattern

A spaghetti point pattern object.

nstepsint

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

permutationsint

The number of permutations to perform. Default is 99.

thresholdfloat

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

distributionstr

The distribution from which random points are sampled Either "uniform" or "poisson".

lowerboundfloat

The lower bound at which the K-function is computed. Default is 0.

upperboundfloat

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

Returns
NetworkKspaghetti.analysis.NetworkK

A network K class instance.

Notes

Based on [Rip77], [OSullivanU10], [OY01], and [OS12b].

[note from `jlaura`] Both the G and K functions generate a full distance matrix. This is because, I know that the full generation is correct and I believe that the truncated generated, e.g. nearest neighbor, has a bug.

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)

Simulate observations along the network.

>>> schools = ntw.pointpatterns[pt_str]
>>> sim = ntw.simulate_observations(schools.npoints)

Compute a network constrained K-function of schools with 5 permutations and 10 nsteps.

>>> kres = ntw.NetworkK(schools, permutations=5, nsteps=10)
>>> kres.lowerenvelope.shape[0]
10
allneighbordistances(self, sourcepattern, destpattern=None, fill_diagonal=None, n_processes=1, gen_tree=False, snap_dist=False)[source]

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{str, spaghetti.PointPattern}

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

destpatternstr

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

fill_diagonal{float, 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{int, 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_treebool

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

snap_distbool

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

Returns
nearestnumpy.ndarray

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

tree_nearestdict

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]
(nan, 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(self, x, y, arc)[source]

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

Parameters
xfloat

The x-coordinate of the snapped point.

yfloat

The y-coordinate of the snapped point.

arctuple

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

Returns
d1float

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

d2float

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

compute_snap_dist(self, pattern, idx)[source]

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

Parameters
patternspaghetti.PointPattern

The point pattern object.

idxint

The point ID.

Returns
distfloat

The euclidean distance from original location to the snapped location.

contiguityweights(self, graph=True, weightings=None, weights_kws={})[source]

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

Parameters
graphbool

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

weightings{dict, None}

Dictionary of lists of weightings for each arc/edge.

weights_kwsdict

Keyword arguments for libpysal.weights.W.

Returns
Wlibpysal.weights.W

A W representing the binary adjacency of the network.

Notes

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

Examples

Instantiate a network.

>>> import spaghetti
>>> from libpysal import examples
>>> import esda
>>> 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)

Using the W object, access to esda functionality is provided. First, a vector of attributes is created for all edges with observations.

>>> w = ntw.contiguityweights(graph=False)
>>> arcs = w.neighbors.keys()
>>> y = numpy.zeros(len(arcs))
>>> for i, e in enumerate(arcs):
...     if e in counts.keys():
...         y[i] = counts[e]

Fetch the number of observations associated with arc 3, where 3 is the basic 0-indexed ID of w.neighbors.keys() created through enumerate(arcs).

>>> y[3]
3.0

Next, a standard call to esda.Moran is made and the result placed into res.

>>> res = esda.moran.Moran(y, w, permutations=99)
>>> type(res)
<class 'esda.moran.Moran'>

Compute the counts per arc or edge (link).

Parameters
obs_ondict

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

Returns
countsdict

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(self, threshold, n_processes=1, gen_tree=False)[source]

Create distance-based weights.

Parameters
thresholdfloat

Distance threshold value.

n_processes{int, 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_treebool

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

Returns
wlibpysal.weights.W

A W object representing the binary adjacency of the network.

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
>>> 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)

Show the number of units in the W object.

>>> w.n
230

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

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

Returns the arcs (links) adjacent to vertices.

Parameters
v0int

The vertex ID.

Returns
linkslist

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(self)[source]

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(self, n_processes, gen_tree=False)[source]

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

Parameters
n_processesint

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_treebool

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

Notes

Based on [Dij59] and [OS12a].

identify_components(self, w, graph=False)[source]

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

Parameters
wlibpysal.weights.W

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

graphbool

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

static loadnetwork(filename)[source]

Load a network from a binary file saved on disk.

Parameters
filenamestr

The filename where the network is saved.

Returns
selfspaghetti.Network

A pre-computed spaghetti network object.

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

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

Parameters
sourcepatternstr

The key of a point pattern snapped to the network.

destpatternstr

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

n_processes{int, 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_treebool

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

all_distsnumpy.ndarray

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

snap_distbool

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

keep_zero_distbool

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
nearestdict

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], 165.33982412719126), ([19], 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], 165.33982412719126), ([11], 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(self, filename)[source]

Save a network to disk as a binary file.

Parameters
filenamestr

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(self, tree, pp_orig, pp_dest=None, n_processes=1)[source]

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

Parameters
treedict

See tree_nearest in spaghetti.Network.allneighbordistances().

pp_origstr

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

pp_deststr

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

n_processesint

See n_processes in spaghetti.Network.full_distance_matrix().

Returns
pathslist

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(self, count, distribution='uniform')[source]

Generate a simulated point pattern on the network.

Parameters
countint

The number of points to create or mean of the distribution if not "uniform".

distributionstr

Either a "uniform" or "poisson" distribution of random points. If "poisson", the distribution is calculated from half the total network length.

Returns
random_ptsdict

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

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(self, in_data, name, idvariable=None, attribute=False)[source]

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, str}

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

namestr

Name to be assigned to the point dataset.

idvariablestr

Column name to be used as the ID variable.

attributebool

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

Notes

See [GFH19] 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(self, distance)[source]

Split all of the arcs in the network at a fixed distance.

Parameters
distancefloat

The distance at which arcs are split.

Returns
split_networkspaghetti.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