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

Misc Issues PR #70

Merged
merged 12 commits into from
May 19, 2021
Merged

Misc Issues PR #70

merged 12 commits into from
May 19, 2021

Conversation

herbiebradley
Copy link
Member

This PR contains several miscellaneous features:

  • Minor linting and type hinting improvements, including making type hints of class labels consistently Union[int, str].
  • Pin Rasterio to 1.1.8
  • New _add_nodes function in geograph.
  • Fix the merge_classes function by detecting neighbouring polygons of the same class and merging them. Closes Merge polygons in the GeoGraph merge_classes function #44
  • Support for barrier_classes in add_habitat, with basic pathfinding functionality. This will only detect pathfinding problems if the polygon of the barrier node completely cuts the buffered polygon of the main node in half, preventing all access to the neighbouring polygon. This works by using Shapely's polygon difference function, see the comments for the actual algorithm.

The pathfinding code slows add_habitat down quite a bit, as might be expected, but it seems to make some difference to the final edge count:
habitats

When this one is merged I will create the 0.0.2 release, upload it to PyPi and add it to Zenodo.

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
Copy link
Collaborator

@Croydon-Brixton Croydon-Brixton left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks already very good to me, thank you for the effort to add a first iteration of the path finding algorithm and getting the ball rolling!
I added a couple of questions regarding edge cases. You documented the code amazingly well, it was a pleasure to read as always @herbiebradley ! 🎉

Comment on lines 668 to 679
# Here we loop through all barrier_nbrs and calculate the
# set difference between the buffered polygon and the
# barrier polygon. If this results in multiple polygons,
# then the barrier polygon fully cuts the buffered polygon.
#
# Therefore we find the largest polygon in the result,
# which will contain the original node polygon, and check
# if it intersects the neighbour polygon we're trying to
# reach. If it does not, there is no path.
# If it does, there may be a path or there may not - it
# would require complex pathfinding code to discover, but
# we add the edge anyway.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very nice description! This is incredibly helpful, thank you!

With regards to edge cases, how would the following case be handled:
image

Here if we consider classes 7 and 13 as barriers separately, they do not cut off the access between 2 and 4. If they are considered as a joint barrier however, they will cut off the access. Do I understand it correctly that in this algorithm the barrier polygons would be processed sequentially (i.e. first 2, then 4, ...) and therefore the edge would be added?
Or am I overlooking sth?

If the former is the case, we could go around this by performing a difference between the buffered original polygon and all barrier polygons that intersect with the buffered original polygon first and then checking, as you did, whether the piece that contains the original node will still intersect with the neighbour (or in fact any of its neighbours, this might give us a quite a speedup?)

Copy link
Member Author

@herbiebradley herbiebradley May 19, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea, I implemented this in the latest commit. I got around a 60% speedup, so it's looking good!

Add pypi badge
Copy link
Member

@rdnfn rdnfn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not much more to add beyond Simon's comments... looks great! 🚀

Comment on lines 673 to 674
# Therefore we find the largest polygon in the result,
# which will contain the original node polygon, and check
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is a good enough assumption but note that I don't think this will not always hold. For large travel distances in particular - for example imagine a circular road around a patch and a large travel distance. If we want to be certain we could also check if it overlaps with the original node, but it might not be worth it in terms of computational cost.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point - I realised that it is easier to check which polygon in the MultiPolygon contains a point in the original, like this:

diff = buff_poly - barrier_poly
if isinstance(diff, shapely.geometry.MultiPolygon):
    if len(diff) > 1:
        bools = [poly.contains(repr_point) for poly in diff]
        node_poly = diff[bools.index(True)]
        if not node_poly.intersects(nbr_polygon):
            add_edge = False

This should be of similar speed.

Co-authored-by: Simon Mathis <svm34@cam.ac.uk>
@herbiebradley
Copy link
Member Author

@Croydon-Brixton @rdnfn Thanks for the feedback - all issues have hopefully been resolved now! 🚀

Co-authored-by: Simon Mathis <svm34@cam.ac.uk>
@herbiebradley herbiebradley merged commit 5bc5892 into main May 19, 2021
@herbiebradley herbiebradley deleted the feature/misc-issues branch May 19, 2021 17:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Merge polygons in the GeoGraph merge_classes function
3 participants