UDST / pandana

Pandas Network Analysis by UrbanSim: fast accessibility metrics and shortest paths, using contraction hierarchies :world_map:
http://udst.github.io/pandana
GNU Affero General Public License v3.0
385 stars 84 forks source link

Shortest path length exists but shortest path is empty #166

Closed kaidiwang closed 3 years ago

kaidiwang commented 3 years ago

If you encounter a bug in Pandana please: 1) first search the previously opened issues to see if the problem has already been reported; 2) If not, fill in the template below and tag with the appropriate Type label. You can delete any sections that do not apply.

Description of the bug

Hi there, I am using pandana to construct a network and impute the shortest path length and shortest path. The package can impute the shortest path length but gives an empty shortest path.

Network data (optional)

https://drive.google.com/drive/folders/1JffMd6SH3Fpd1aclNJSLkdBaTuxapu9S?usp=sharing

Environment

Paste the code that reproduces the issue here:

gdf_nodes = geopandas.read_file('nodes_2mile_w_idx.shp')
gdf_nodes.set_index('idx', inplace = True)
gdf_links = geopandas.read_file(links_2mile_w_idx.shp')

net = pdna.Network(
                gdf_nodes['X'], gdf_nodes['Y'], 
                gdf_links['o_nodeidx'], gdf_links['d_nodeidx'], 
                gdf_links[['TIMAU']], twoway = False)
print(net.shortest_path_length(call_client.origin, call_client.destination))
print(net.shortest_path(call_client.origin, call_client.destination))

The output is

4294967.295 []

PyMap commented 3 years ago

Hi @kaidiwang! Just wondering what are you calling with the call_client? If I try both methods getting the nodes from the net object I'm always getting results for both shortest path methods

image

kaidiwang commented 3 years ago

The call_client.origin is 5062 and call_client.destination is 6235.

Hi @kaidiwang! Just wondering what are you calling with the call_client? If I try both methods getting the nodes from the net object I'm always getting results for both shortest path methods

image

PyMap commented 3 years ago

hey @kaidiwang how are you? I found out that what you get with 5062 and 6235 is not happening just for this pair of nodes. There are some other node pairs with the same behavior.

If you look for them in your edges gdf you will see that these pairs are not connected. So, when creating your net object with nodes and edges gdf you are creating a graph where nodes can be connected or not. That's why you get that empty list when calling the shorest path method

PyMap commented 3 years ago

Exploring it further, I would suggest to:

  1. Create the net object from the same source (geodataframe of links):
    
    connected_nodes = np.unique(gdf_links[['o_nodeidx','d_nodeidx']])
    gdf_nodes_ = gdf_nodes.loc[gdf_nodes.index.isin(connected_nodes)].copy()

net_ = pdna.Network(gdfnodes['X'], gdfnodes['Y'], gdf_links['o_nodeidx'], gdf_links['d_nodeidx'], gdf_links[['TIMAU']], twoway = False)

This way, if you try to get the `shortest_path_distance` from non connected nodes you will get a `nan` error as feedback. The nodes are not connected, so the error would be the correct output.

The problem with pandana here is that it returns a `shortest_path_distance` value (that has no sense) instead of 0 or non connected nodes warning.

2. If you want to work with all the nodes (even if some of them are not connected) you can use the `low_connectivity` method:

number_of_edges = len(np.unique(net.edges_df[['from','to']])) number_of_nodes = len(net.nodes_df.index.unique())

directed graph

node_degree = number_of_edges/number_of_nodes max_imp = gdf_links['TIMAU'].max()

low_connected_nodes = net.low_connectivity_nodes(impedance=max_imp, count=node_degree*2)


The low_connected_nodes would be a list of nodes to filter or exclude

(cc @sablanchard @smmaurer )
kaidiwang commented 3 years ago

I see. Thank you!