Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor element_as_gdf internals #724

Merged
merged 4 commits into from
May 24, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 2 additions & 7 deletions spaghetti/network.py
Original file line number Diff line number Diff line change
Expand Up @@ -3060,7 +3060,6 @@ def element_as_gdf(
snapped=False,
routes=None,
id_col="id",
geom_col="geometry",
martinfleis marked this conversation as resolved.
Show resolved Hide resolved
):
"""Return a ``geopandas.GeoDataFrame`` of network elements. This can be
(a) the vertices of a network; (b) the arcs of a network; (c) both the
Expand Down Expand Up @@ -3088,9 +3087,6 @@ def element_as_gdf(
id_col : str
``geopandas.GeoDataFrame`` column name for IDs. Default is ``"id"``.
When extracting routes this creates an (origin, destination) tuple.
geom_col : str
``geopandas.GeoDataFrame`` column name for geometry. Default is
``"geometry"``.

Raises
------
Expand Down Expand Up @@ -3165,7 +3161,7 @@ def element_as_gdf(

# shortest path routes between observations
if routes:
paths = util._routes_as_gdf(routes, id_col, geom_col)
paths = util._routes_as_gdf(routes, id_col)
return paths

# need vertices place holder to create network segment LineStrings
Expand All @@ -3183,7 +3179,6 @@ def element_as_gdf(
pp_name,
snapped,
id_col=id_col,
geom_col=geom_col,
)

# return points geodataframe if arcs not specified or
Expand All @@ -3192,7 +3187,7 @@ def element_as_gdf(
return points

# arcs
arcs = util._arcs_as_gdf(net, points, id_col=id_col, geom_col=geom_col)
arcs = util._arcs_as_gdf(net, points, id_col=id_col)

if vertices_for_arcs:
return arcs
Expand Down
2 changes: 1 addition & 1 deletion spaghetti/tests/test_network.py
Original file line number Diff line number Diff line change
Expand Up @@ -493,7 +493,7 @@ def test_element_as_gdf(self):
_, tree = ntw.allneighbordistances(points1, points2, gen_tree=True)
paths = ntw.shortest_paths(tree, points1, pp_dest=points2)
paths_gdf = spaghetti.element_as_gdf(ntw, routes=paths)
observed_origins = paths_gdf["O"].nunique()
observed_origins = paths_gdf["id"].map(lambda x: x[0]).nunique()
martinfleis marked this conversation as resolved.
Show resolved Hide resolved
assert observed_origins == known_origins

def test_regular_lattice(self):
Expand Down
43 changes: 15 additions & 28 deletions spaghetti/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

try:
import geopandas
import pandas
import shapely
from shapely.geometry import LineString
except ImportError:
Expand Down Expand Up @@ -659,9 +660,7 @@ def build_chains(space_h, space_v, exterior, bounds, h=True):


@requires("geopandas", "shapely")
def _points_as_gdf(
net, vertices, vertices_for_arcs, pp_name, snapped, id_col=None, geom_col=None
):
def _points_as_gdf(net, vertices, vertices_for_arcs, pp_name, snapped, id_col=None):
"""Internal function for returning a point ``geopandas.GeoDataFrame``
called from within ``spaghetti.element_as_gdf()``.

Expand Down Expand Up @@ -743,7 +742,7 @@ def _points_as_gdf(


@requires("geopandas", "shapely")
def _arcs_as_gdf(net, points, id_col=None, geom_col=None):
def _arcs_as_gdf(net, points, id_col=None):
"""Internal function for returning an arc ``geopandas.GeoDataFrame``
called from within ``spaghetti.element_as_gdf()``.

Expand All @@ -762,20 +761,16 @@ def _arcs_as_gdf(net, points, id_col=None, geom_col=None):

"""

# arcs
arcs = {}

# iterate over network arcs
for vtx1_id, vtx2_id in net.arcs:
# extract vertices comprising the network arc
vtx1 = points.loc[(points[id_col] == vtx1_id), geom_col].squeeze()
vtx2 = points.loc[(points[id_col] == vtx2_id), geom_col].squeeze()
# create a LineString for the network arc
arcs[(vtx1_id, vtx2_id)] = LineString((vtx1, vtx2))
def _line_coords(loc):
return (
(points.loc[loc[0]].geometry.x, points.loc[loc[0]].geometry.y),
(points.loc[loc[1]].geometry.x, points.loc[loc[1]].geometry.y),
)

# instantiate GeoDataFrame
arcs = geopandas.GeoDataFrame(
sorted(list(arcs.items())), columns=[id_col, geom_col]
arcs = pandas.DataFrame(zip(sorted(net.arcs)), columns=[id_col])
arcs = arcs.set_geometry(
shapely.linestrings(arcs[id_col].map(_line_coords).values.tolist())
martinfleis marked this conversation as resolved.
Show resolved Hide resolved
)

# additional columns
Expand All @@ -786,7 +781,7 @@ def _arcs_as_gdf(net, points, id_col=None, geom_col=None):


@requires("geopandas", "shapely")
def _routes_as_gdf(paths, id_col, geom_col):
def _routes_as_gdf(paths, id_col):
"""Internal function for returning a shortest paths
``geopandas.GeoDataFrame`` called from within
``spaghetti.element_as_gdf()``.
Expand All @@ -807,17 +802,9 @@ def _routes_as_gdf(paths, id_col, geom_col):

"""

# isolate the origins, destinations, and geometries
origs = [o for (o, d), g in paths]
dests = [d for (o, d), g in paths]
geoms = [LineString(g.vertices) for (o, d), g in paths]

# instantiate as a geodataframe
paths = geopandas.GeoDataFrame(geometry=geoms)
paths["O"] = origs
paths["D"] = dests

if id_col:
paths[id_col] = paths.apply(lambda x: (x["O"], x["D"]), axis=1)
paths = dict(paths)
ids, geoms = zip(paths.keys()), [LineString(g.vertices) for g in paths.values()]
jGaboardi marked this conversation as resolved.
Show resolved Hide resolved
paths = geopandas.GeoDataFrame(ids, columns=[id_col], geometry=geoms)

return paths