osmnx icon indicating copy to clipboard operation
osmnx copied to clipboard

Include parking space data in nodes

Open EwoutH opened this issue 5 months ago • 4 comments

Contributing guidelines

  • [X] I understand the contributing guidelines

Documentation

  • [X] My proposal is not addressed by the documentation or examples

Existing issues

  • [X] Nothing similar appears in an existing issue

What problem does your feature proposal solve?

Currently OSMnx does not directly associate parking spaces with nearby nodes in the street network. Users interested in urban planning, traffic flow analysis, or transportation research often need detailed information about parking availability near specific locations. This includes data on different types of parking (car, motorcycle, bicycle), the nature of these parking spaces (public vs. private), and their capacity.

What is your proposed solution?

I propose an enhancement to OSMnx that automatically associates parking spaces with the nearest nodes. Key features of this enhancement would include:

  1. Type Distinction: Differentiate between car, motorcycle, and bicycle parking.
  2. Public/Private Distinction: Distinguish between public and private parking facilities.
  3. Inferred Capacity: Infer the number of parking places from the area of the parking facility if the exact number is unknown.
  4. Default Node Assignment: Assign all parking spaces to the closest node using a Voronoi-based approach.
  5. Radius Argument: Introduce a radius parameter to only include parking spaces within a certain maximum distance from each node.
  6. Simplification Options: Provide options to merge the number of nearby parking spaces when simplifying networks.
  7. Data Storage: Store parking data at each node, either as an integer (total number of spaces for each type) or as a dictionary including the number of spaces and their distance from the node.

What alternatives have you considered?

Currently, users have to manually process OpenStreetMap data to associate parking information with nodes, which is time-consuming and inefficient. There are no known alternatives within OSMnx that offer this functionality.

Additional context

A typical use case might involve urban planners wanting to analyze the accessibility of parking near commercial areas. They would benefit from being able to quickly assess the availability of different types of parking (e.g., bicycle vs. car) within walking distance from key nodes.

Example Code:

import osmnx as ox

place = "Delft, Netherlands"
G = ox.graph_from_place(place, network_type='drive')

# Proposed function enhancement
G = ox.add_parking_to_nodes(G, max_radius=500, parking_types=['car', 'motorcycle', 'bicycle'], only_public=True, include_distances=False)

In this example, the add_parking_to_nodes function would be an enhancement to OSMnx, automatically fetching and associating parking data with the closest nodes, with a maximum of 500-meter of each node. The function would differentiate between car, motorcycle, and bicycle parking, providing an integrated view of parking availability and capacity around each node in the network. This functionality would significantly help in urban and transportation planning research, allowing for a more comprehensive analysis of parking impacts on traffic flow and urban accessibility.

EwoutH avatar Jan 14 '24 13:01 EwoutH

@EwoutH thanks and sorry for the delay. I'm still reflecting on this proposal. One thing I'm thinking about is if this could be generalized to a attach_features_to_nodes function that would take arbitrary OSM features and add them to the nearest nodes. If it could be generalized in such a way, this could be a broadly useful enhancement.

gboeing avatar Jan 21 '24 18:01 gboeing

Thanks! That's an excellent idea, it might also be useful to see what stores, parks, public transport stops, bodies of water or anything else is close to certain nodes.

On thing that might be difficult is how to generalize. For example, in the case of parking spots I might want to know how many there are, so I want to take the sum of capacity. But simultaneously I want to keep bike and car parking separate. Maybe we can make some aggregation function for if there are multiple, for example.

EwoutH avatar Jan 21 '24 21:01 EwoutH

Simplest way is just to start with adding the feature data and doing aggregation manually.

So if I want to add parking spaces to a node:

# Proposed function enhancement
G = ox.add_parking_to_nodes(G, max_radius=500, parking_types=['car', 'motorcycle', 'bicycle'], only_public=True, include_distances=False) 

You might get something like this:

# Example representation of parking spaces at a node
print(G.edges[0][1].feature_data)
[
    {
        'feature_type': 'Parking Lot',
        'capacity': 20,
        'fee': True,
        'accessible': True,  # Whether the parking lot is accessible to all
        'security_level': 'High',  # Security level of the parking lot
        'electric_charging': False  # Whether electric vehicle charging is available
    },
    {
        'feature_type': 'Bicycle Rack',
        'capacity': 10,
        'covered': False,  # Whether the bicycle rack is covered
        'secured': True  # Whether the bicycle rack is secured
    },
    {
        'feature_type': 'Motorcycle Parking',
        'capacity': 5,
        'fee': False,
        'covered': True,  # Whether the motorcycle parking is covered
        'security_level': 'Medium'  # Security level of the motorcycle parking
    }
]

And then users can aggerate the data however they like, and maybe in the future we could support some simple functions for it.

EwoutH avatar Jan 29 '24 16:01 EwoutH

I'll have some time to take a considered look at this soon.

gboeing avatar Jan 29 '24 16:01 gboeing

Ok, I've had some time to reflect on this. In general, the OSMnx project follows 3 principles when adding new functionality: 1) it is useful to a broad set of users, 2) it generalizes well, and 3) it is not trivially easy for users to implement themselves. Your proposal satisfies point 1 but I don't think it satisfies points 2 and 3. Let me explain my thinking...

Let's say you create a street network graph and a GeoDataFrame of features, like this:

import osmnx as ox
import pandas as pd
place = "Piedmont, CA, USA"
G = ox.graph.graph_from_place(place, network_type="drive")
features = ox.features.features_from_place(place, {"amenity": "parking"})

It is trivially easy to attach your features to your graph's nearest nodes as attributes:

nn = ox.distance.nearest_nodes(G, features.centroid.x, features.centroid.y)
useful_tags = ["access", "parking", "surface", "capacity", "fee"]
for node, feature in zip(nn, features[useful_tags].to_dict(orient="records")):
    feature = {k: v for k, v in feature.items() if pd.notna(v)}
    G.nodes[node].update({"parking": feature})

I didn't initially consider how simple it would be to implement a basic version of this when I first read your proposal. Furthermore, I can imagine nearly infinite variation in how users would proceed from here with aggregation or customized attachment for their specific analytical goals. Because it's trivially easy to implement in just a few lines of code and it needs extreme flexibility to proceed from there for various analyses, this seems like the ideal use case to demonstrate in the examples gallery rather than building into the codebase itself.

Long story short: I think it's a great use case for OSMnx but is best served in the examples gallery rather than as a new feature in the codebase. A basic implementation is trivially simple, and a sufficiently flexible implementation to capture all use cases would be overly complex.

gboeing avatar Mar 02 '24 07:03 gboeing

See https://github.com/gboeing/osmnx-examples/issues/83

gboeing avatar Mar 02 '24 07:03 gboeing

Thanks for getting back! I also didn't realise it would be this simple, in that case I agree an example is more than sufficient.

EwoutH avatar Mar 02 '24 08:03 EwoutH