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

Support loading and/or merging multiple networks #1140

Closed
3 tasks done
EwoutH opened this issue Mar 5, 2024 · 5 comments
Closed
3 tasks done

Support loading and/or merging multiple networks #1140

EwoutH opened this issue Mar 5, 2024 · 5 comments

Comments

@EwoutH
Copy link
Contributor

EwoutH commented Mar 5, 2024

Contributing guidelines

  • I understand the contributing guidelines

Documentation

  • My proposal is not addressed by the documentation or examples

Existing issues

  • Nothing similar appears in an existing issue

What problem does your feature proposal solve?

When working with OpenStreetMap (OSM) data for urban planning or transportation analysis, it is often necessary to work with specific areas at different levels of detail or to combine data from multiple regions into a single network. Currently, merging two or more networks in OSMnx requires manual effort and a good understanding of both OSMnx and NetworkX. This process can be unintuitive and time-consuming, especially for users who need to efficiently merge networks with overlapping areas while ensuring that duplicates (nodes and edges with the same OSMIDs) are properly handled.

What is your proposed solution?

I propose adding built-in functionality to OSMnx that allows users to load and merge two or more graphs/networks directly within the library. This functionality should:

  1. Enable the easy combination of networks by automatically handling geographic projection alignment, ensuring that the networks are in the same coordinate reference system.
  2. Provide an option to merge networks with overlapping areas in such a way that duplicates are identified and resolved based on user-defined criteria (e.g., keeping the more detailed edge where overlaps occur).
  3. Include the ability to specify how properties of overlapping edges and nodes should be merged (e.g., averaging weights, summing lengths, choosing the maximum or minimum of conflicting attributes).

What alternatives have you considered?

Currently, the workaround involves manually using NetworkX functions to combine the graphs and then iterating over the combined graph to remove duplicates. This process is not only cumbersome but also prone to errors, especially for users not deeply familiar with the intricacies of NetworkX or the specific data structure conventions used by OSMnx.

Additional context

When working with OpenStreetMap (OSM) data for urban planning or transportation analysis, it A minimal working example of the current approach to merging two networks, highlighting the complexity and manual steps involved:

import osmnx as ox
import networkx as nx

# Define custom filters for two different detail levels
filter_high = '["highway"~"motorway|trunk|primary|secondary|tertiary"]'
filter_low = '["highway"~"motorway|trunk"]'

# Load two networks with different filters
network_high = ox.graph_from_place('Area A, City, Country', custom_filter=filter_high)
network_low = ox.graph_from_place('Area B, City, Country', custom_filter=filter_low)

# Manually merge and handle duplicates - steps not shown due to complexity

# Desired built-in functionality
# merged_network = ox.merge_networks(network_high, network_low, method='union', resolve_duplicates='smart')

Picture1

@gboeing
Copy link
Owner

gboeing commented Mar 6, 2024

Thanks for this suggestion. The OSMnx project follows three principles when adding new functionality: 1) it is useful for a broad set of users, 2) it generalizes well, and 3) it is not trivially easy for users to implement themselves. Your proposal would offer some powerful functionality, but I believe it's outside the scope of the project.

Most users merging multiple networks can do so in one line of code with nx.compose(). If they have an edge use case that cannot be done in a one-liner (such as your examples of handling duplicates, dealing with overlaps, averaging weights, summing attributes, processing conflicts, etc), writing their own custom code seems like the proper solution. That is, we cannot presume a generalized solution to this problem, because there are innumerable possible analytical directions a user may wish to take it. The goal of OSMnx is to give them the tools to write their own code to solve such edge case problems.

@gboeing gboeing closed this as not planned Won't fix, can't repro, duplicate, stale Mar 6, 2024
@EwoutH
Copy link
Contributor Author

EwoutH commented Mar 9, 2024

Thanks for getting back!

Most users merging multiple networks can do so in one line of code with nx.compose().

That was indeed my first approach. But then I noticed that no edges or nodes were removed. After an intense debugging session, I figured it was because I wanted to merge after simplifications. That messes up all the node and edge IDs, especially after consolidating intersections.

If I find a good approach for differential simplification I think is worth sharing, I will do somewhere with an example.

@EwoutH
Copy link
Contributor Author

EwoutH commented Mar 10, 2024

Having slept on it I think the proper location to tackle this is at the simplification stage. So, you would get your networks, add an attribute to them to recognize them (i.e. "networks"), compose them directly with nx.compose().

A good, broadly useful way to integrate this might be by adding a filter_attrs argument to selectively simplify graph elements based on attribute criteria. So for example, you say something like:

simplify_graph(G, filter_attrs={"network": "The Hague"})

in which filter_attrs is a dictionary specifying node and edge attributes for inclusion in simplification. Then, only nodes and edges matching filter_attrs are considered in the simplification process. The default would be None, meaning all nodes and edges are included without filtering.

Would you be open for something like this?

@gboeing
Copy link
Owner

gboeing commented Mar 10, 2024

The proposed resolution discussed in #1127 would allow users to retain nodes in a simplified graph based on the attributes of the node or its incident edges. I suspect that resolution will probably help in use cases similar to this. And for more complicated use cases, a customized rather than built-in solution is probably appropriate.

@EwoutH
Copy link
Contributor Author

EwoutH commented Mar 10, 2024

It could be indeed integrated in that one. I think here I propose it a bit broader: Both consolidate_intersections and simplify_graph could get a filter_attrs dict, which could both be a specific type of junction not to merge or node or edge attribute entirely.

I think some open questions are:

  1. When simplifying/consolidating, when do we consider node attributes, when edge attributes, and when both?
  2. Do we allow filter_attrs to be callables, like a lambda function?
    filter_attrs={"maxspeed": lambda x: 10 < x < 40}
  3. Currently, you can't simplify multiple times. We probably want to track that on a node/edge level, to allow simplifying different parts of the network to different extends.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants