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, 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_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. Default is dict().

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

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))
[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__(in_data=None, vertex_sig=11, unique_arcs=True, extractgraph=True, w_components=True, weightings=False, weights_kws={}, vertex_atol=None)[source]

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

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:
pointpatternspaghetti.PointPattern

A spaghetti point pattern object.

nstepsint

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

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%). Default is 0.5.

distributionstr

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

upperboundfloat

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

Returns:
GlobalAutoKspaghetti.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)[source]

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_namestr

The name of the point pattern in question.

permutationsint

The number of permutations to perform. Default is 999.

graphbool

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

Returns:
moranesda.Moran

A Moran’s I statistic object results.

ylist

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)
0.005193
allneighbordistances(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(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(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(graph=True, weightings=None, from_split=False, 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. Default is None.

from_splitbool

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

weights_kwsdict

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

Returns:
Wlibpysal.weights.W

A W representing the binary adjacency of the network.

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)

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>)]}.

graphbool

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

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(threshold, n_processes=1, gen_tree=False, weights_kws={})[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.

weights_kwsdict

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

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
>>> 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]
(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()[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(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(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(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(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(tree, pp_orig, pp_dest=None)[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.

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

Generate a simulated point pattern on the network.

Parameters:
countint

The number of points to create.

distributionstr

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

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(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 [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={})[source]

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

Parameters:
split_param{int, float}

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

split_bystr

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

w_componentsbool

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

weights_kwsdict

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

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

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