Python Forum
Finding nearest point of a Multidigraph in Python 3.7
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Finding nearest point of a Multidigraph in Python 3.7
#1
I have two point layers, one with bus stops and train stations, and another with playground centrepoints.
From QGIS I created a cleaned up network containing roads and footpaths, which I have converted to a multidigraph in Python. This so I can loop through each bus/train station and find the network to the playground point, if there is one.

The problem is trying to get the closest edge node to the playground spits out an error.

path = "C:\\........\\Footpath_Roads_Extended_Python.shp"
def read_multi_shp(path): #create multidigraph
    """
    copied from read_shp, but allowing MultiDiGraph instead.
    """
    try:
        from osgeo import ogr
    except ImportError:
        raise ImportError("read_shp requires OGR: http://www.gdal.org/")

    net = nx.MultiDiGraph()

    def getfieldinfo(lyr, feature, flds):
            f = feature
            return [f.GetField(f.GetFieldIndex(x)) for x in flds]

    def addlyr(lyr, fields):
        for findex in range(lyr.GetFeatureCount()):
            f = lyr.GetFeature(findex)
            flddata = getfieldinfo(lyr, f, fields)
            g = f.geometry()
            attributes = dict(zip(fields, flddata))
            attributes["ShpName"] = lyr.GetName()
            if g.GetGeometryType() == 1:  # point
                net.add_node((g.GetPoint_2D(0)), attributes)
            if g.GetGeometryType() == 2:  # linestring
                attributes["Wkb"] = g.ExportToWkb()
                attributes["Wkt"] = g.ExportToWkt()
                attributes["Json"] = g.ExportToJson()
                last = g.GetPointCount() - 1
                net.add_edge(g.GetPoint_2D(0), g.GetPoint_2D(last), attr_dict=attributes)

    if isinstance(path, str):
        shp = ogr.Open(path)
        lyrcount = shp.GetLayerCount()
        for lyrindex in range(lyrcount):
            lyr = shp.GetLayerByIndex(lyrindex)
            flds = [x.GetName() for x in lyr.schema]
            addlyr(lyr, flds)
	
    return net

H=read_multi_shp(path)

PTV_Playground_Shortest_Path_300_400 = []
while i < len(PTV_Playground_Joined_initial): #loop through playgrounds and find nearest path node

	orig_xy = (df.loc[i,"PTV_N"], "-"+df.loc[i,"PTV_E"])

	target_xy = (df.loc[i,"Playgroun1"], df.loc[i,"Playground"])
	
	orig_node = ox.get_nearest_node(H, orig_xy, method='euclidean') #H seems to cause the error.................
The error I receive is

Traceback (most recent call last):
  File "C:\Users\geogjo\Desktop\PythonTraining\Network_Analysis_Test.py", line 100, in <module>
    orig_node = ox.get_nearest_node(H, orig_xy, method='euclidean')
  File "C:\Users\geogjo\AppData\Local\Continuum\anaconda3\lib\site-packages\osmnx\utils.py", line 461, in get_nearest_node
    coords = [[node, data['x'], data['y']] for node, data in G.nodes(data=True)]
  File "C:\Users\geogjo\AppData\Local\Continuum\anaconda3\lib\site-packages\osmnx\utils.py", line 461, in <listcomp>
    coords = [[node, data['x'], data['y']] for node, data in G.nodes(data=True)]
KeyError: 'x'
I snapped all linework to itself to keep it as simple as possible. When I test the type it says it's a multidigraph.
Yes you can use QGIS shortest path tools but only if you have one end point or one start point. This has many start and end points so I will be looping through each.
Reply
#2
The error tells you that there is no key 'x' in data which you get from G.nodes()
So i would look what i get back from G.nodes()
Reply
#3
When I print the multi-digraph that is being passed into this function it looks like the following...

[(327688.2817133684, 5739552.011543424), (341508.08128750307, 5767378.745506252), (341481.1308291708, 5767277.219589586), (341364.9730373633, 5767271.420884848), (341364.8637279594, 5767271.415428021), (341374.82312183146, 5767212.4025153965) etc.....

Does this look correct. The error is coming from utils.
Reply
#4
I can´t tell you, i don´t know.
You are calling ox.get_nearest_node(H, orig_xy, method='euclidean') and then you get the error.

So either parameter H, which comes from H = read_multi_shp(path)
or orig_xy which comes from orig_xy = (df.loc[i, "PTV_N"], "-" + df.loc[i, "PTV_E"]) is faulty.
I would guess it´s the building of orig_xy, are you sure about the part above marked red?
Reply
#5
It is coming from H. It looks like I need to add keys for X and Y with the corresponding values. At the moment it is just coordinates i.e. (1,2) without a key value, whereas I think it should be (X:1, Y:2). How can I do that in a multidigraph created from a shp?
Reply
#6
H = [(1,2), (2,3), (1,3), (3,2), (3,4)]

new_H = {'x': [], 'y': []}
for x, y in H:
    new_H['x'].append(x)
    new_H['y'].append(y)

print(new_H)

# {'x': [1, 2, 1, 3, 3], 'y': [2, 3, 3, 2, 4]}
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  Get numpy ceil and floor value for nearest two decimals klllmmm 4 1,198 Jun-07-2023, 07:35 AM
Last Post: paul18fr
  compare and find the nearest element ? mr_gentle_sausage 4 1,003 Jan-15-2023, 07:11 AM
Last Post: DPaul
  finding point in m grid jenya56 0 797 Feb-06-2022, 09:00 PM
Last Post: jenya56
  Python Matplotlib: How do I plot lines with different end point in the same graph? JaneTan 0 1,550 Feb-28-2021, 11:56 AM
Last Post: JaneTan
  Rounding to the nearest eight wallgraffiti 2 2,019 Jul-15-2020, 06:05 PM
Last Post: wallgraffiti
  Finding Max and Min Values Associated with Unique Identifiers in Python ubk046 1 2,011 May-08-2020, 12:04 PM
Last Post: anbu23
  connecting the first point to the last point Matplotlib omar_mohsen 0 4,525 Jan-15-2020, 01:23 PM
Last Post: omar_mohsen
  finding the closest floating point number in a list Skaperen 17 8,113 Sep-19-2019, 10:39 PM
Last Post: Skaperen
  finding the next higher representable floating point value Skaperen 0 1,916 Sep-13-2019, 11:16 PM
Last Post: Skaperen
  find nearest number d3fi 7 3,879 Aug-26-2019, 09:32 PM
Last Post: ichabod801

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020