question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

STRtree Nearest method always returns one geometry

See original GitHub issue

Create two points that are equidistant to a Line.

from shapely.strtree import STRtree
from shapely import wkt
from shapely.geometry import box, Point, LineString

keys = []
keys.append(Point(1.5, 3))
keys.append(Point(1, 2.5))

query = LineString([Point(1,2),Point(3,4)])

for i, g in enumerate(keys):
    bbox_intersects = box(*g.bounds).intersects(query)
    print(i, bbox_intersects, g.distance(query))

# 0 False 0.3535533905932738
# 1 False 0.3535533905932738

Create the tree and query for the nearest neighbor. Only one geometry will be returned.

tree = STRtree(keys)
result = tree.nearest(query)

print(result)

# POINT (1 2.5)

Does anyone know of an efficient workaround that always guarantees the nearest neighbor between two geometries and doesn’t yield false negatives?

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Comments:9 (4 by maintainers)

github_iconTop GitHub Comments

1reaction
tomplexcommented, Aug 19, 2020

Ah, I see what you’re saying. In that case I would probably try something like:

  • start by querying the tree for the bounding box of the geometry of interest
  • if no results are returned, increase the size bounding box by some set amount and re-query. Figuring out the right amount will probably be the difficult part here and will depend on the density and distribution of your dataset.
  • if results are returned, find all results which are the minimum distance from the geometry of interest. This will require a distance calculation for all returned results.

this gist describes what I mean. It returns both points for a couple of different symmetric situations like the one you posted above:

Screen Shot 2020-08-18 at 10 58 31 PM

0reactions
carlosg-mcommented, Aug 19, 2020

@tomplex, I’ve adapted your fantastic solution to my problem.

This is probably python’s only rtree solution for exact nearest neighbors search that guarantees 100% recall and generalizes to multiple geometries.

I wasn’t able to test performance, but I hope it scales to couple million geometries.

Once again thank you!

Example dataset:

from shapely.strtree import STRtree
from shapely import wkt
from shapely.geometry import box, Point, LineString
import numpy as np

keys = []
keys.append(Point(1.5, 3))
keys.append(Point(1, 2.5))
keys.append(Point(3.3, 5.5))
keys.append(LineString([Point(-1,-2),Point(6,7)]))

query = LineString([Point(1,2),Point(3,4)])

for i, g in enumerate(keys):
    bbox_intersects = box(*g.bounds).intersects(query)
    print(i, bbox_intersects, g.distance(query))

# 0 False 0.3535533905932738
# 1 False 0.3535533905932738
# 2 False 1.5297058540778354
# 3 True 0.5262348115842175
  • Create STRtree
  • Query STRtree for the first nearest neighbor
  • Get distance to first nearest neighbor
  • Expand query geometry bounding box to include minimum distance
  • Query STRtree for all geometries that intersect previously created bounding box
  • Search for false positives, filter candidate geometries that are greater than minimum distance
tree = STRtree(keys)
result = tree.nearest(query)
min_distance = result.distance(query)

def _expand(geom, amt):
    amt = amt + np.finfo(np.float64).eps
    bounds = geom.bounds
    bounds = (bounds[0] - amt, bounds[1] - amt, bounds[2] + amt, bounds[3] + amt)
    return box(*bounds)

bbox_search = _expand(query, min_distance)
result = tree.query(bbox_search)

print([g.wkt for g in result])

# ['POINT (1 2.5)', 'LINESTRING (-1 -2, 6 7)', 'POINT (1.5 3)']
Read more comments on GitHub >

github_iconTop Results From Across the Web

STRtree Nearest method always returns one geometry #967
Create the tree and query for the nearest neighbor. Only one geometry will be returned. tree = STRtree(keys) result = tree.nearest(query) print( ...
Read more >
STRTree — Shapely 2.0.0 documentation - Read the Docs
Return the index of the nearest geometry in the tree for each input geometry based on distance within two-dimensional Cartesian space.
Read more >
Index (org.locationtech.jts:jts-core 1.18.0 API)
Computes the closest points on two line segments. closestPoints(Geometry, Geometry) - Static method in class org.locationtech.jts.operation.distance.
Read more >
Shapely Documentation - Read the Docs
Note: These methods will always return a geometric object. An intersection of disjoint ... Returns the nearest geometry in strtree to geom.
Read more >
Index (JTS Topology Suite version 1.12) - Tsusiat Software
CentroidLine: Adds the linear components of by a Geometry to the centroid total. add(Coordinate[]) ... Method in class com.vividsolutions.jts.index.strtree.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found