Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ jobs:
url: https://pypi.org/project/bikenetlib/

steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v7

- name: Build package
run: |
Expand Down
19 changes: 0 additions & 19 deletions .github/workflows/release-please.yml

This file was deleted.

17 changes: 9 additions & 8 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ jobs:
caching:
strategy:
matrix:
python-version: ["3.12"]
python-version: ["3.11", "3.15"]
os: [ubuntu-latest]
fail-fast: false
env:
Expand All @@ -34,13 +34,13 @@ jobs:
name: Cache for ${{ matrix.python-version }} on ${{ matrix.os }}
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v7

- name: Get week number
run: echo "WEEK=$(date +'%V')" >> $GITHUB_ENV

- name: Set up Python ${{ matrix.python-version }}
uses: mamba-org/setup-micromamba@v2
uses: mamba-org/setup-micromamba@v3
with:
create-args: python=${{ matrix.python-version }}
environment-file: environment-dev.yml
Expand All @@ -51,12 +51,13 @@ jobs:
needs: caching
strategy:
matrix:
python-version: ["3.12"]
python-version: ["3.11", "3.15"]
os: [ubuntu-latest]
submodule:
#- { name: "io", pytest_args: "tests/test_io.py" } # To do
# - { name: "io", pytest_args: "tests/test_io.py" } # To do
# - { name: "osm", pytest_args: "tests/test_osm.py" } # To do
- { name: "utils", pytest_args: "tests/test_utils.py" }
#- { name: "viz", pytest_args: "tests/test_viz.py" } # To do
# - { name: "viz", pytest_args: "tests/test_viz.py" } # To do
fail-fast: false

name: ${{ matrix.submodule.name }} (${{ matrix.python-version }} on ${{ matrix.os }})
Expand All @@ -67,13 +68,13 @@ jobs:
shell: bash -el {0}

steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v7

- name: Get week number
run: echo "WEEK=$(date +'%V')" >> $GITHUB_ENV

- name: Set up Python ${{ matrix.python-version }}
uses: mamba-org/setup-micromamba@v2
uses: mamba-org/setup-micromamba@v3
with:
create-args: python=${{ matrix.python-version }}
environment-file: environment-dev.yml
Expand Down
6 changes: 3 additions & 3 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,14 @@ repos:
- id: mixed-line-ending
- id: check-illegal-windows-names

- repo: https://github.com/pre-commit/mirrors-prettier
rev: "v3.1.0"
- repo: https://github.com/pre-commit/pre-commit
rev: "v4.6.2"
hooks:
- id: prettier
types_or: [markdown, yaml]
- repo: https://github.com/astral-sh/ruff-pre-commit
# Ruff version.
rev: v0.15.12
rev: v0.17.0
hooks:
# Run the linter.
- id: ruff
Expand Down
3 changes: 0 additions & 3 deletions .release-please-manifest.json

This file was deleted.

2 changes: 1 addition & 1 deletion bikenetlib/_version.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
"""bikenetlib package version."""

__version__ = "0.5.0" # x-release-please-version
__version__ = "0.5.0"
58 changes: 1 addition & 57 deletions bikenetlib/io.py
Original file line number Diff line number Diff line change
@@ -1,57 +1 @@
import geopandas as gpd
import osmnx as ox

def prepare_network(city_name, proj_crs, network_type='all_public', custom_filter=None, retain_all=True, city_boundary_file=None):
"""Download and prepare a street network from OSM via OSMnx

Downloads a network with a given network_type and custom_filter using ox.graph_from_place.
Then, stores the undirected OSM data in gdfs and projects using proj_crs.

Parameters
----------
city_name : str
Name of the city that the analysis should be performed on. Overruled (for data fetching) if city_boundary_file is set.
proj_crs : str
Coordinate reference system that is used to project osm data.
network_type : {β€œall”, β€œall_public”, β€œbike”, β€œdrive”, β€œdrive_service”, β€œwalk”}
What type of street network to retrieve if custom_filter is None.
custom_filter : (str | list[str] | None)
A custom ways filter to be used instead of the network_type presets
retain_all : bool, default True
If True, return the entire graph even if it is not connected, useful for disconnected bicycle networks. If False, retain only the largest weakly connected component, useful for road networks.
city_boundary_file : (str | None), default None
If not set to None, the study area will be selected from the (Multi)Polygon provided in the city_boundary_file shape file. For example, "copenhagen.shp".

Returns
-------
nodes : geopandas.geodataframe.GeoDataFrame
Extracted OSM nodes, projected
edges : geopandas.geodataframe.GeoDataFrame
Extracted OSM edges, projected
g_undir : networkx.classes.multigraph.MultiGraph
Extracted networkX graph, undirected
"""

# Fetch street network data from osmnx
if city_boundary_file is None:
g = ox.graph_from_place(
city_name, network_type=network_type, custom_filter=custom_filter, retain_all=retain_all
)
else:
shp = gpd.read_file(city_boundary_file)
city_boundary_polygon = shp.iloc[0].geometry
g = ox.graph_from_polygon(
city_boundary_polygon, network_type=network_type, custom_filter=custom_filter, retain_all=retain_all
)

g_undir = g.to_undirected().copy() # convert to undirected (dropping OSMnx keys!)

# Export osmnx data to gdfs
nodes, edges = nx_to_nodes_edges(g_undir, proj_crs)
return nodes, edges, g_undir

def download_pois(): # To develop
pass

def save_to_file(): # To develop
pass
"""Import/Output functions of `bikenetlib`."""
72 changes: 72 additions & 0 deletions bikenetlib/osm.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
"""Global constants for `bikenetlib` related to OpenStreetMap(OSM).

GROWABLE_NETWORK_CUSTOM_FILTER : list[str] or None
Custom filter for all infrastructure elements that are considered as
growable by `growbikenet`. By default, `growbikenet` uses a custom filter
to retrieve the combined drive and pbi (protected bicycle infrastructure)
network. To only consider the drive network, set
`GROWABLE_NETWORK_CUSTOM_FILTER` to None and `GROWABLE_NETWORK_TYPE` to
'drive'. However, doing so can lead to issues:
https://github.com/BikeNetKit/GrowBikeNet/issues/255.
GROWABLE_NETWORK_TYPE : {'drive', 'all', 'all_public', 'bike', 'drive_service', 'walk'}, default 'drive'
What type of street network to retrieve for the growable network if `GROWABLE_NETWORK_CUSTOM_FILTER` is None.
PBI_CUSTOM_FILTER : list[str]
Custom filter for protected bicycle infrastructure (pbi).
PBI_DICT : dict
Dictionary for protected bicycle infrastructure (pbi), for single criteria.
PBI_DICT_SUB : dict
Dictionary for protected bicycle infrastructure (pbi), with one
sub-criterion. For example, highway~path AND bicycle~designated. Always
adds a second criterion access!~private.
"""

# Populate ox.settings.useful_tags_way to make application of custom filter possible
import osmnx as ox
for custom_tag in ["highway", "cycleway", "bicycle", "cycleway:right", "cycleway:left", "cycleway:both", "cyclestreet", "access", "area", "service", "motor_vehicle", "motorcar"]: # This list should contain all tags used in any custom filters
if custom_tag not in ox.settings.useful_tags_way:
ox.settings.useful_tags_way.extend(custom_tag)


GROWABLE_NETWORK_CUSTOM_FILTER = [ # adapted from https://github.com/gboeing/osmnx/blob/2fc39cb2792ff869881b99f724a2d97f0e958667/osmnx/_overpass.py#L77
# Car infra - Instead of excluding what we don't want, we only include what we want. Note: we are OK with alleys and driveways
'["highway"~"motorway|trunk|primary|secondary|tertiary|residential|motorway_link|trunk_link|primary_link|secondary_link|tertiary_link|service|unclassified"]["highway"!~"abandoned|construction|no|planned|platform|proposed|raceway|razed|rest_area|services"]["service"!~"emergency_access|parking|parking_aisle|private"]["area"!~"yes"]["access"!~"private"]["motor_vehicle"!~"no"]["motorcar"!~"no"]',
# Bike infra, copied from PBI_CUSTOM_FILTER
'["highway"~"cycleway|living_street"]',
'["highway"~"path|pedestrian|footway"]["bicycle"~"designated|yes|permissive"]["access"!~"private"]',
'["cyclestreet"~"yes"]',
'["bicycle_road"~"yes"]',
'["cycleway"~"track"]',
'["cycleway:right"~"track|opposite_track"]', # opposite_track is deprecated, but could still exist
'["cycleway:left"~"track|opposite_track"]', # opposite_track is deprecated, but could still exist
'["cycleway:both"~"track|opposite_track"]', # opposite_track is deprecated, but could still exist
]

GROWABLE_NETWORK_TYPE = 'drive'

PBI_CUSTOM_FILTER = [
'["highway"~"cycleway|living_street"]',
'["highway"~"path|pedestrian|footway"]["bicycle"~"designated|yes|permissive"]["access"!~"private"]',
'["cyclestreet"~"yes"]',
'["bicycle_road"~"yes"]',
'["cycleway"~"track"]',
'["cycleway:right"~"track|opposite_track"]', # opposite_track is deprecated, but could still exist
'["cycleway:left"~"track|opposite_track"]', # opposite_track is deprecated, but could still exist
'["cycleway:both"~"track|opposite_track"]', # opposite_track is deprecated, but could still exist
]

PBI_DICT = {
'highway': ['cycleway','living_street'],
'cyclestreet': ['yes'],
'bicycle_road': ['yes'],
'cycleway': ['track'],
'cycleway:right': ['track','opposite_track'],
'cycleway:left': ['track','opposite_track'],
'cycleway:both': ['track','opposite_track'],
}
PBI_DICT_SUB = {
'highway': [
['path','pedestrian','footway'],
{'bicycle': ['designated','yes','permissive']},
]
}

Loading