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
88 changes: 88 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
name: Test

on:
push:
branches: # on all branches except `typos`
- "**"
- "!typos"
paths-ignore:
- "docs/**"
- "examples/**"
- "data/**"
- ".git*"
- "README.md"
pull_request:
branches:
- "**"
schedule: # Every Monday at 04:00 UTC
- cron: "0 4 * * 1"

jobs:
caching:
strategy:
matrix:
python-version: ["3.12"]
os: [ubuntu-latest]
fail-fast: false
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true

defaults:
run:
shell: bash -elo pipefail {0}

name: Cache for ${{ matrix.python-version }} on ${{ matrix.os }}
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v6

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

- name: Set up Python ${{ matrix.python-version }}
uses: mamba-org/setup-micromamba@v2
with:
create-args: python=${{ matrix.python-version }}
environment-file: environment-dev.yml
cache-environment: true
cache-environment-key: W${{ env.WEEK }}

run-tests:
needs: caching
strategy:
matrix:
python-version: ["3.12"]
os: [ubuntu-latest]
submodule:
#- { name: "io", pytest_args: "tests/test_io.py" } # To do
- { name: "utils", pytest_args: "tests/test_utils.py" }
#- { name: "viz", pytest_args: "tests/test_viz.py" } # To do
fail-fast: false

name: ${{ matrix.submodule.name }} (${{ matrix.python-version }} on ${{ matrix.os }})
runs-on: ${{ matrix.os }}
timeout-minutes: 60
defaults:
run:
shell: bash -el {0}

steps:
- uses: actions/checkout@v6

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

- name: Set up Python ${{ matrix.python-version }}
uses: mamba-org/setup-micromamba@v2
with:
create-args: python=${{ matrix.python-version }}
environment-file: environment-dev.yml
cache-environment: true
cache-environment-key: W${{ env.WEEK }}

- name: Install bikenetlib
run: pip install --no-build-isolation --no-deps -e .

- name: "Run tests ${{ matrix.submodule.name }}"
run: |
pytest ${{ matrix.submodule.pytest_args }}
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# Bikeβ€ŠNetβ€ŠKit / Bikeβ€ŠNetβ€ŠLib

[![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)
[![code style: prettier](https://img.shields.io/badge/code_style-prettier-ff69b4.svg?style=flat-square)](https://github.com/prettier/prettier)
[![pre-commit](https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit&logoColor=white)](https://github.com/pre-commit/pre-commit)
[![Test](https://github.com/BikeNetKit/BikeNetLib/actions/workflows/test.yml/badge.svg?branch=main)](https://github.com/BikeNetKit/BikeNetLib/actions/workflows/test.yml)

> [!WARNING]
> This repository is under heavy development and not yet functional. Do not use.

Expand Down
52 changes: 0 additions & 52 deletions bikenetlib/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -236,58 +236,6 @@ def update_seed_points_with_existing_bike_network(seed_points_snapped, nodes_exn
seed_points_snapped.set_index("osmid", drop=False, inplace=True)
return seed_points_snapped

def get_grid_seed_points(edges, seed_point_spacing, principal_bearing):
"""Get grid seed points for street network, rotated by principal bearing

Adapted from: https://github.com/gboeing/osmnx-examples/blob/v0.11/notebooks/17-street-network-orientations.ipynb

Parameters
----------
edges: geopandas.geodataframe.GeoDataFrame
The street network, in a projected coordinate reference system
seed_point_spacing: int
Distance between seed points, in meters
principal_bearing: float
Principal bearing (most common bearing of streets)

Returns
-------
seed_points: geopandas.geodataframe.GeoDataFrame
Seed points, rotated by principal bearing, to be snapped, in the same projected coordinate reference system as edges
"""

# Rotate edges counter to the principal bearing
edges_temp = edges.copy()
edges_temp.geometry = edges_temp.geometry.rotate(principal_bearing, origin=(0, 0))

# Create grid
# get convex hull around edge area
hull = edges_temp.union_all().convex_hull
# get bounds of hull
xmin, ymin, xmax, ymax = hull.bounds

# https://stackoverflow.com/questions/66010964/fastest-way-to-produce-a-grid-of-points-that-fall-within-a-polygon-or-shape
# Populate hull bbox with evenly spaced seeding points
points = []
for x in np.arange(xmin, xmax, seed_point_spacing):
for y in np.arange(ymin, ymax, seed_point_spacing):
points.append(Point((round(x, 4), round(y, 4))))

# Keep only those seed points that are within the hull polygon
prep_polygon = prep(hull)
valid_points = []
valid_points.extend(filter(prep_polygon.contains, points))

# store seed points in gdf
seed_points = gpd.GeoDataFrame({"geometry": valid_points}, crs=edges.crs)

# Rotate points back using the principal bearing
seed_points.geometry = seed_points.geometry.rotate(
-1 * principal_bearing, origin=(0, 0)
)

return seed_points


def get_principal_bearing(G):
"""Determine the most common (principal) bearing, for the best grid orientation.
Expand Down
Binary file added tests/test_data/copenhagen.dbf
Binary file not shown.
1 change: 1 addition & 0 deletions tests/test_data/copenhagen.prj
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137,298.257223563]],PRIMEM["Greenwich",0],UNIT["Degree",0.017453292519943295]]
1 change: 1 addition & 0 deletions tests/test_data/copenhagen.qpj
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
GEOGCS["WGS 84",DATUM["WGS_1984",SPHEROID["WGS 84",6378137,298.257223563,AUTHORITY["EPSG","7030"]],AUTHORITY["EPSG","6326"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4326"]]
Binary file added tests/test_data/copenhagen.shp
Binary file not shown.
Binary file added tests/test_data/copenhagen.shx
Binary file not shown.
Binary file added tests/test_data/oelde_grid.gpkg
Binary file not shown.
Binary file added tests/test_data/oelde_growbikenet.gpkg
Binary file not shown.
Binary file added tests/test_data/oelde_streets.gpkg
Binary file not shown.
13 changes: 13 additions & 0 deletions tests/test_io.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import pytest
import osmnx as ox
import pandas as pd
import geopandas as gpd
from pandas.testing import assert_frame_equal
from bikenetlib.io import (
prepare_network,
download_pois,
save_to_file,
)
from shapely.geometry import Point, LineString, MultiLineString

# To do
88 changes: 88 additions & 0 deletions tests/test_utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import pytest
import osmnx as ox
import pandas as pd
import geopandas as gpd
from pandas.testing import assert_frame_equal
from bikenetlib.utils import ( # List them in the order appearing in utils.py
intersects_properly,
get_principal_bearing,
filter_seed_points,
)
from shapely.geometry import Point, LineString, MultiLineString


# intersects_properly

@pytest.fixture
def geom_1():
linestring = LineString([(0, 0), (1, 1), (2, 2)])
return linestring


@pytest.fixture
def geom_2():
linestring = LineString([(3, 3), (4, 4), (5, 5)])
return linestring


def test_intersects_properly(geom_1, geom_2):
assert intersects_properly(geom_1, geom_2) is False


# filter_seed_points

@pytest.fixture
def seed_point_delta():
return 500


@pytest.fixture
def snapped_seed_points():
d = {
"osmid": ["1", "2", "3"],
"geometry_generated": [Point(1000, 1000), Point(2000, 2000), Point(3000, 3000)],
}
gdf = gpd.GeoDataFrame(d, geometry="geometry_generated", crs="EPSG:3857")
gdf["geometry_osm"] = gpd.GeoSeries(
[Point(1001, 1001), Point(10000, 10000), Point(3001, 3001)], crs="EPSG:3857"
)
return gdf


@pytest.fixture
def filtered_seed_points():
d = {"osmid": ["1", "3"], "geometry": [Point(1001, 1001), Point(3001, 3001)]}
gdf = gpd.GeoDataFrame(d, geometry="geometry", crs="EPSG:3857")
gdf = gdf.set_index("osmid")
gdf["osmid"] = gdf.index
gdf = gdf.iloc[:, [1, 0]]
return gdf


def test_filter_seed_points(
snapped_seed_points, filtered_seed_points, seed_point_delta
):
assert_frame_equal(
filter_seed_points(snapped_seed_points, seed_point_delta),
filtered_seed_points,
check_dtype=False,
)


# get_principal_bearing

@pytest.fixture
def validation_streets():
streets_nodes = gpd.read_file(
"./tests/test_data/oelde_streets.gpkg", layer="nodes"
).set_index("osmid")
streets_edges = gpd.read_file(
"./tests/test_data/oelde_streets.gpkg", layer="edges"
).set_index(["u", "v", "key"])
streets = ox.convert.graph_from_gdfs(streets_nodes, streets_edges)
return streets


def test_get_principal_bearing(validation_streets):
assert get_principal_bearing(validation_streets) == 65.0

1 change: 1 addition & 0 deletions tests/test_viz.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# To do
Loading