diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml new file mode 100644 index 0000000..9b61aab --- /dev/null +++ b/.github/workflows/docs.yml @@ -0,0 +1,75 @@ +name: Docs + +on: + push: + branches: + - main + - dow_workflow + paths: + - "fixbikenet/**" + - "docs/**" + - "logging.cfg" + + # Allows you to run this workflow manually from the Actions tab + workflow_dispatch: + +# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages +permissions: + contents: read + pages: write + id-token: write + +# Allow one concurrent deployment +concurrency: + group: "pages" + cancel-in-progress: true + +jobs: + generate-deploy-docs: + strategy: + matrix: + python-version: ["3.12"] + os: [ubuntu-latest] + name: Generate documentation + runs-on: ${{ matrix.os }} + env: + FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true + environment: + name: Deploy to github pages + url: ${{ steps.deployment.outputs.page_url }} + defaults: + run: + shell: bash -el {0} + steps: + - name: Check out Git repository + 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: Add Notebook Kernel + run: python -m ipykernel install --user --name fixbikenet --display-name "Python (fixbikenet)" + + # - name: Generating .rst files + # run: sphinx-apidoc -o docs/api/ fixbikenet/ + - name: Generating html + run: sphinx-build docs/source/ public -b dirhtml + + - name: Setup Pages + uses: actions/configure-pages@v5 + - name: Upload artifact + uses: actions/upload-pages-artifact@v4 + with: + # Upload generated html + path: "public/" + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v4 diff --git a/.gitignore b/.gitignore index ae849e6..edd770c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,266 @@ +# Folders +data/ +results/ +cache/ +examples/*.gpkg +/*.gpkg + +# Created by https://www.toptal.com/developers/gitignore/api/visualstudiocode,python,macos,windows +# Edit at https://www.toptal.com/developers/gitignore?templates=visualstudiocode,python,macos,windows + +### macOS ### +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +### macOS Patch ### +# iCloud generated files +*.icloud + +### Python ### +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + # pixi environments .pixi/* !.pixi/config.toml +pixi* + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# poetry +# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control +#poetry.lock + +# pdm +# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. +#pdm.lock +# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it +# in version control. +# https://pdm.fming.dev/#use-with-ide +.pdm.toml + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# PyCharm +# JetBrains specific template is maintained in a separate JetBrains.gitignore that can +# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore +# and can be added to the global gitignore or merged into this file. For a more nuclear +# option (not recommended) you can uncomment the following to ignore the entire idea folder. +#.idea/ + +### Python Patch ### +# Poetry local configuration file - https://python-poetry.org/docs/configuration/#local-configuration +poetry.toml + +# ruff +.ruff_cache/ + +# LSP config files +pyrightconfig.json + +### VisualStudioCode ### +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +!.vscode/*.code-snippets + +# Local History for Visual Studio Code +.history/ + +# Built Visual Studio Code Extensions +*.vsix + +### VisualStudioCode Patch ### +# Ignore all local history of files +.history +.ionide + +### Windows ### +# Windows thumbnail cache files +Thumbs.db +Thumbs.db:encryptable +ehthumbs.db +ehthumbs_vista.db + +# Dump file +*.stackdump + +# Folder config file +[Dd]esktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msix +*.msm +*.msp + +# Windows shortcuts +*.lnk + +# End of https://www.toptal.com/developers/gitignore/api/visualstudiocode,python,macos,windows diff --git a/FixBIkeViz.ipynb b/FixBIkeViz.ipynb index e797507..134fcd3 100644 --- a/FixBIkeViz.ipynb +++ b/FixBIkeViz.ipynb @@ -121,7 +121,7 @@ "text": [ "/var/folders/q4/95x26cls17s1z694v56lw3hh0000gn/T/ipykernel_62426/2585542112.py:17: UserWarning: The GeoDataFrame you are attempting to plot is empty. Nothing has been displayed.\n", " edges_gdf[edges_gdf.intersects(gap_gdf.union_all())].plot(ax=ax, color = \"black\", zorder = 1, lw = 0)\n", - "/Users/jqz304/miniconda3/envs/growbikenet/lib/python3.12/site-packages/contextily/tile.py:662: UserWarning: The inferred zoom level of 38 is not valid for the current tile provider (valid zooms: 0 - 20).\n", + "/Users/jqz304/miniconda3/envs/fixbikenet/lib/python3.12/site-packages/contextily/tile.py:662: UserWarning: The inferred zoom level of 38 is not valid for the current tile provider (valid zooms: 0 - 20).\n", " warnings.warn(msg)\n" ] }, @@ -141,7 +141,7 @@ "text": [ "/var/folders/q4/95x26cls17s1z694v56lw3hh0000gn/T/ipykernel_62426/2585542112.py:17: UserWarning: The GeoDataFrame you are attempting to plot is empty. Nothing has been displayed.\n", " edges_gdf[edges_gdf.intersects(gap_gdf.union_all())].plot(ax=ax, color = \"black\", zorder = 1, lw = 0)\n", - "/Users/jqz304/miniconda3/envs/growbikenet/lib/python3.12/site-packages/contextily/tile.py:662: UserWarning: The inferred zoom level of 39 is not valid for the current tile provider (valid zooms: 0 - 20).\n", + "/Users/jqz304/miniconda3/envs/fixbikenet/lib/python3.12/site-packages/contextily/tile.py:662: UserWarning: The inferred zoom level of 39 is not valid for the current tile provider (valid zooms: 0 - 20).\n", " warnings.warn(msg)\n" ] }, @@ -181,7 +181,7 @@ "text": [ "/var/folders/q4/95x26cls17s1z694v56lw3hh0000gn/T/ipykernel_62426/2585542112.py:17: UserWarning: The GeoDataFrame you are attempting to plot is empty. Nothing has been displayed.\n", " edges_gdf[edges_gdf.intersects(gap_gdf.union_all())].plot(ax=ax, color = \"black\", zorder = 1, lw = 0)\n", - "/Users/jqz304/miniconda3/envs/growbikenet/lib/python3.12/site-packages/contextily/tile.py:662: UserWarning: The inferred zoom level of 39 is not valid for the current tile provider (valid zooms: 0 - 20).\n", + "/Users/jqz304/miniconda3/envs/fixbikenet/lib/python3.12/site-packages/contextily/tile.py:662: UserWarning: The inferred zoom level of 39 is not valid for the current tile provider (valid zooms: 0 - 20).\n", " warnings.warn(msg)\n" ] }, @@ -219,7 +219,7 @@ "name": "stderr", "output_type": "stream", "text": [ - "/Users/jqz304/miniconda3/envs/growbikenet/lib/python3.12/site-packages/contextily/tile.py:662: UserWarning: The inferred zoom level of 21 is not valid for the current tile provider (valid zooms: 0 - 20).\n", + "/Users/jqz304/miniconda3/envs/fixbikenet/lib/python3.12/site-packages/contextily/tile.py:662: UserWarning: The inferred zoom level of 21 is not valid for the current tile provider (valid zooms: 0 - 20).\n", " warnings.warn(msg)\n" ] }, @@ -257,7 +257,7 @@ "name": "stderr", "output_type": "stream", "text": [ - "/Users/jqz304/miniconda3/envs/growbikenet/lib/python3.12/site-packages/contextily/tile.py:662: UserWarning: The inferred zoom level of 21 is not valid for the current tile provider (valid zooms: 0 - 20).\n", + "/Users/jqz304/miniconda3/envs/fixbikenet/lib/python3.12/site-packages/contextily/tile.py:662: UserWarning: The inferred zoom level of 21 is not valid for the current tile provider (valid zooms: 0 - 20).\n", " warnings.warn(msg)\n" ] }, @@ -307,7 +307,7 @@ "text": [ "/var/folders/q4/95x26cls17s1z694v56lw3hh0000gn/T/ipykernel_62426/2585542112.py:17: UserWarning: The GeoDataFrame you are attempting to plot is empty. Nothing has been displayed.\n", " edges_gdf[edges_gdf.intersects(gap_gdf.union_all())].plot(ax=ax, color = \"black\", zorder = 1, lw = 0)\n", - "/Users/jqz304/miniconda3/envs/growbikenet/lib/python3.12/site-packages/contextily/tile.py:662: UserWarning: The inferred zoom level of 38 is not valid for the current tile provider (valid zooms: 0 - 20).\n", + "/Users/jqz304/miniconda3/envs/fixbikenet/lib/python3.12/site-packages/contextily/tile.py:662: UserWarning: The inferred zoom level of 38 is not valid for the current tile provider (valid zooms: 0 - 20).\n", " warnings.warn(msg)\n" ] }, @@ -327,7 +327,7 @@ "text": [ "/var/folders/q4/95x26cls17s1z694v56lw3hh0000gn/T/ipykernel_62426/2585542112.py:17: UserWarning: The GeoDataFrame you are attempting to plot is empty. Nothing has been displayed.\n", " edges_gdf[edges_gdf.intersects(gap_gdf.union_all())].plot(ax=ax, color = \"black\", zorder = 1, lw = 0)\n", - "/Users/jqz304/miniconda3/envs/growbikenet/lib/python3.12/site-packages/contextily/tile.py:662: UserWarning: The inferred zoom level of 38 is not valid for the current tile provider (valid zooms: 0 - 20).\n", + "/Users/jqz304/miniconda3/envs/fixbikenet/lib/python3.12/site-packages/contextily/tile.py:662: UserWarning: The inferred zoom level of 38 is not valid for the current tile provider (valid zooms: 0 - 20).\n", " warnings.warn(msg)\n" ] }, @@ -377,7 +377,7 @@ "text": [ "/var/folders/q4/95x26cls17s1z694v56lw3hh0000gn/T/ipykernel_62426/2585542112.py:17: UserWarning: The GeoDataFrame you are attempting to plot is empty. Nothing has been displayed.\n", " edges_gdf[edges_gdf.intersects(gap_gdf.union_all())].plot(ax=ax, color = \"black\", zorder = 1, lw = 0)\n", - "/Users/jqz304/miniconda3/envs/growbikenet/lib/python3.12/site-packages/contextily/tile.py:662: UserWarning: The inferred zoom level of 39 is not valid for the current tile provider (valid zooms: 0 - 20).\n", + "/Users/jqz304/miniconda3/envs/fixbikenet/lib/python3.12/site-packages/contextily/tile.py:662: UserWarning: The inferred zoom level of 39 is not valid for the current tile provider (valid zooms: 0 - 20).\n", " warnings.warn(msg)\n" ] }, @@ -445,7 +445,7 @@ "name": "stderr", "output_type": "stream", "text": [ - "/Users/jqz304/miniconda3/envs/growbikenet/lib/python3.12/site-packages/contextily/tile.py:662: UserWarning: The inferred zoom level of 21 is not valid for the current tile provider (valid zooms: 0 - 20).\n", + "/Users/jqz304/miniconda3/envs/fixbikenet/lib/python3.12/site-packages/contextily/tile.py:662: UserWarning: The inferred zoom level of 21 is not valid for the current tile provider (valid zooms: 0 - 20).\n", " warnings.warn(msg)\n" ] }, @@ -475,7 +475,7 @@ "text": [ "/var/folders/q4/95x26cls17s1z694v56lw3hh0000gn/T/ipykernel_62426/2585542112.py:17: UserWarning: The GeoDataFrame you are attempting to plot is empty. Nothing has been displayed.\n", " edges_gdf[edges_gdf.intersects(gap_gdf.union_all())].plot(ax=ax, color = \"black\", zorder = 1, lw = 0)\n", - "/Users/jqz304/miniconda3/envs/growbikenet/lib/python3.12/site-packages/contextily/tile.py:662: UserWarning: The inferred zoom level of 40 is not valid for the current tile provider (valid zooms: 0 - 20).\n", + "/Users/jqz304/miniconda3/envs/fixbikenet/lib/python3.12/site-packages/contextily/tile.py:662: UserWarning: The inferred zoom level of 40 is not valid for the current tile provider (valid zooms: 0 - 20).\n", " warnings.warn(msg)\n" ] }, @@ -515,7 +515,7 @@ "text": [ "/var/folders/q4/95x26cls17s1z694v56lw3hh0000gn/T/ipykernel_62426/2585542112.py:17: UserWarning: The GeoDataFrame you are attempting to plot is empty. Nothing has been displayed.\n", " edges_gdf[edges_gdf.intersects(gap_gdf.union_all())].plot(ax=ax, color = \"black\", zorder = 1, lw = 0)\n", - "/Users/jqz304/miniconda3/envs/growbikenet/lib/python3.12/site-packages/contextily/tile.py:662: UserWarning: The inferred zoom level of 39 is not valid for the current tile provider (valid zooms: 0 - 20).\n", + "/Users/jqz304/miniconda3/envs/fixbikenet/lib/python3.12/site-packages/contextily/tile.py:662: UserWarning: The inferred zoom level of 39 is not valid for the current tile provider (valid zooms: 0 - 20).\n", " warnings.warn(msg)\n" ] }, @@ -535,7 +535,7 @@ "text": [ "/var/folders/q4/95x26cls17s1z694v56lw3hh0000gn/T/ipykernel_62426/2585542112.py:17: UserWarning: The GeoDataFrame you are attempting to plot is empty. Nothing has been displayed.\n", " edges_gdf[edges_gdf.intersects(gap_gdf.union_all())].plot(ax=ax, color = \"black\", zorder = 1, lw = 0)\n", - "/Users/jqz304/miniconda3/envs/growbikenet/lib/python3.12/site-packages/contextily/tile.py:662: UserWarning: The inferred zoom level of 39 is not valid for the current tile provider (valid zooms: 0 - 20).\n", + "/Users/jqz304/miniconda3/envs/fixbikenet/lib/python3.12/site-packages/contextily/tile.py:662: UserWarning: The inferred zoom level of 39 is not valid for the current tile provider (valid zooms: 0 - 20).\n", " warnings.warn(msg)\n" ] }, @@ -555,7 +555,7 @@ "text": [ "/var/folders/q4/95x26cls17s1z694v56lw3hh0000gn/T/ipykernel_62426/2585542112.py:17: UserWarning: The GeoDataFrame you are attempting to plot is empty. Nothing has been displayed.\n", " edges_gdf[edges_gdf.intersects(gap_gdf.union_all())].plot(ax=ax, color = \"black\", zorder = 1, lw = 0)\n", - "/Users/jqz304/miniconda3/envs/growbikenet/lib/python3.12/site-packages/contextily/tile.py:662: UserWarning: The inferred zoom level of 40 is not valid for the current tile provider (valid zooms: 0 - 20).\n", + "/Users/jqz304/miniconda3/envs/fixbikenet/lib/python3.12/site-packages/contextily/tile.py:662: UserWarning: The inferred zoom level of 40 is not valid for the current tile provider (valid zooms: 0 - 20).\n", " warnings.warn(msg)\n" ] }, @@ -605,7 +605,7 @@ "text": [ "/var/folders/q4/95x26cls17s1z694v56lw3hh0000gn/T/ipykernel_62426/2585542112.py:17: UserWarning: The GeoDataFrame you are attempting to plot is empty. Nothing has been displayed.\n", " edges_gdf[edges_gdf.intersects(gap_gdf.union_all())].plot(ax=ax, color = \"black\", zorder = 1, lw = 0)\n", - "/Users/jqz304/miniconda3/envs/growbikenet/lib/python3.12/site-packages/contextily/tile.py:662: UserWarning: The inferred zoom level of 37 is not valid for the current tile provider (valid zooms: 0 - 20).\n", + "/Users/jqz304/miniconda3/envs/fixbikenet/lib/python3.12/site-packages/contextily/tile.py:662: UserWarning: The inferred zoom level of 37 is not valid for the current tile provider (valid zooms: 0 - 20).\n", " warnings.warn(msg)\n" ] }, @@ -777,7 +777,7 @@ ], "metadata": { "kernelspec": { - "display_name": "growbikenet", + "display_name": "fixbikenet", "language": "python", "name": "python3" }, diff --git a/FixBikeMVP.ipynb b/FixBikeMVP.ipynb index ce246c0..a076788 100644 --- a/FixBikeMVP.ipynb +++ b/FixBikeMVP.ipynb @@ -749,7 +749,7 @@ ], "metadata": { "kernelspec": { - "display_name": "growbikenet", + "display_name": "fixbikenet", "language": "python", "name": "python3" }, diff --git a/README.md b/README.md index 4bcfabd..0bceb76 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,10 @@ # Bike Net Kit / Fix Bike Net -[![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) -[![Docs](https://github.com/BikeNetKit/FixBikeNet/actions/workflows/docs.yml/badge.svg)](https://github.com/BikeNetKit/FixBikeNet/actions/workflows/docs.yml) +[![Docs](https://github.com/BikeNetKit/FixBikeNet/actions/workflows/docs.yml/badge.svg)](https://bikenetkit.github.io/FixBikeNet/) [![Test](https://github.com/BikeNetKit/FixBikeNet/actions/workflows/test.yml/badge.svg?branch=main)](https://github.com/BikeNetKit/FixBikeNet/actions/workflows/test.yml) +[![PyPI - Version](https://img.shields.io/pypi/v/fixbikenet)](https://pypi.org/project/FixBikeNet/) +[![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) +![Human created](https://raw.githubusercontent.com/BikeNetKit/.github/refs/heads/main/profile/_static/badge_humancreated.svg) The Python package `fixbikenet` identifies the most important gaps to fill in a city's bicycle network. @@ -18,119 +18,25 @@ The software downloads and pre-processes data from OpenStreetMap, identifies the ### The easy way -> [!IMPORTANT] -> As of 2026-05-27, the conda-forge installation is not yet working. We will remove this note once it works. - -The best way to install FixBikeNet is using [`conda`](https://docs.conda.io/projects/conda/en/latest/index.html) and the `conda-forge` channel: - -``` -conda install -c conda-forge fixbikenet -``` - -### Advanced installations -#### Set up environment - -The main step is to set up a virtual environment `fbnenv` in which to install the package, and then to use or run the environment. - -##### With Pixi - -Installation with [`Pixi`](https://pixi.prefix.dev/latest/) is fastest and most stable: - -``` -pixi init fbnenv -pixi add --pypi fixbikenet -``` - -At this point you can run fixbikenet in the environment, for example as such: - -``` -pixi run python examples/mwe.py -``` - -> [!NOTE] -> The first time you run code with Pixi, it might take a minute longer, as Pixi resolves the environment's dependencies only at this point. - -_Alternatively_, or if you run into issues, [clone this repository](https://github.com/BikeNetKit/fixbikenet/archive/refs/heads/main.zip) and create the environment via the [`environment.yml`](environment.yml) file: - -``` -pixi init --import environment.yml -``` - -##### With mamba/conda/pip - -Alternatively to Pixi, use [`mamba`](https://mamba.readthedocs.io/en/latest/index.html) or [`conda`](https://docs.conda.io/projects/conda/en/latest/index.html). - -
Instructions - -> [!IMPORTANT] -> As of 2026-05-06, the conda-forge installation is not yet working. We will remove this note once it works. - -``` -mamba create -n fbnenv -c conda-forge fixbikenet -mamba activate fbnenv -``` - -_Alternatively_, or if you run into issues, [clone this repository](https://github.com/BikeNetKit/fixbikenet/archive/refs/heads/main.zip) and create the environment via the [`environment.yml`](environment.yml) file: +The currently default way to install FixBikeNet is using pip: ``` -mamba env create --file environment.yml -mamba activate fbnenv pip install fixbikenet ``` -
- -### Run fixbikenet in Jupyter lab + -If you want to develop the project, [clone this repository](https://github.com/BikeNetKit/fixbikenet/archive/refs/heads/main.zip) and create the environment via the [`environment-dev.yml`](environment-dev.yml) file: +If this does not work, consult our [installation docs](https://bikenetkit.github.io/FixBikeNet/installation/). -``` -pixi init --import environment-dev.yml -``` - -The developemt environment is called `fbnenvdev`. Make sure to also read [our contribution guidelines](https://github.com/BikeNetKit/FixBikeNet?tab=contributing-ov-file). +### Advanced and development installations + See our [installation docs](https://bikenetkit.github.io/FixBikeNet/installation/) for details. ## Usage @@ -139,21 +45,12 @@ We provide a minimum working example in two formats: - Python script ([examples/mwe.py](examples/mwe.py)) - Jupyter notebook ([examples/mwe.ipynb](examples/mwe.ipynb)) -## Repository structure +## Docs +Find more information in our docs: [https://bikenetkit.github.io/FixBikeNet/](https://bikenetkit.github.io/FixBikeNet/) -``` -├── fixbikenet <- Packaged functions and visualizations -├── tests <- Tests to execute to ensure functionality -├── .gitignore <- Files and folders ignored by git -├── .pre-commit-config.yaml <- Pre-commit hooks used -├── README.md -├── environment.yml <- Environment file to set up the environment using conda/mamba/pixi -``` -## Credits +## Supported by +Development of BikeNetKit/FixBikeNet was supported by the [Innovation Fund Denmark](https://innovationsfonden.dk/en) and the EU HORIZON project [JUST STREETS](https://www.just-streets.eu). - -Development of FixBikeNet was supported by the Danish Innovation Fund (Innovationsfonden). +[![Innovation Fund Denmark](https://raw.githubusercontent.com/BikeNetKit/.github/refs/heads/main/profile/_static/logo_innovationfund.png)](https://innovationsfonden.dk/en)    [![European Union](https://raw.githubusercontent.com/BikeNetKit/.github/refs/heads/main/profile/_static/logo_eu.png)](https://commission.europa.eu/index_en)   [![JUST STREETS](https://raw.githubusercontent.com/BikeNetKit/.github/refs/heads/main/profile/_static/logo_juststreets.png)](https://www.just-streets.eu/) diff --git a/docs/Makefile b/docs/Makefile new file mode 100644 index 0000000..92dd33a --- /dev/null +++ b/docs/Makefile @@ -0,0 +1,20 @@ +# Minimal makefile for Sphinx documentation +# + +# You can set these variables from the command line, and also +# from the environment for the first two. +SPHINXOPTS ?= +SPHINXBUILD ?= sphinx-build +SOURCEDIR = source +BUILDDIR = _build + +# Put it first so that "make" without argument is like "make help". +help: + @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +.PHONY: help Makefile + +# Catch-all target: route all unknown targets to Sphinx using the new +# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). +%: Makefile + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/docs/make.bat b/docs/make.bat new file mode 100644 index 0000000..83cf06c --- /dev/null +++ b/docs/make.bat @@ -0,0 +1,35 @@ +@ECHO OFF + +pushd %~dp0 + +REM Command file for Sphinx documentation + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build +) +set SOURCEDIR=source +set BUILDDIR=_build + +%SPHINXBUILD% >NUL 2>NUL +if errorlevel 9009 ( + echo. + echo.The 'sphinx-build' command was not found. Make sure you have Sphinx + echo.installed, then set the SPHINXBUILD environment variable to point + echo.to the full path of the 'sphinx-build' executable. Alternatively you + echo.may add the Sphinx directory to PATH. + echo. + echo.If you don't have Sphinx installed, grab it from + echo.https://www.sphinx-doc.org/ + exit /b 1 +) + +if "%1" == "" goto help + +%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% +goto end + +:help +%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% + +:end +popd diff --git a/docs/requirements.txt b/docs/requirements.txt new file mode 100644 index 0000000..6944a6b --- /dev/null +++ b/docs/requirements.txt @@ -0,0 +1 @@ +furo==2025.12.19 diff --git a/docs/source/_static/logo_eu.png b/docs/source/_static/logo_eu.png new file mode 100644 index 0000000..2467c67 Binary files /dev/null and b/docs/source/_static/logo_eu.png differ diff --git a/docs/source/_static/logo_innovationfund.png b/docs/source/_static/logo_innovationfund.png new file mode 100644 index 0000000..e81be74 Binary files /dev/null and b/docs/source/_static/logo_innovationfund.png differ diff --git a/docs/source/_static/logo_juststreets.png b/docs/source/_static/logo_juststreets.png new file mode 100644 index 0000000..a2ff05e Binary files /dev/null and b/docs/source/_static/logo_juststreets.png differ diff --git a/docs/source/_static/references.bib b/docs/source/_static/references.bib new file mode 100644 index 0000000..3ea2e28 --- /dev/null +++ b/docs/source/_static/references.bib @@ -0,0 +1,20 @@ +@article{szell2022gub, + title = {Growing urban bicycle networks}, + author = {Szell, Michael and Mimar, Sayat and Perlman, Tyler and Ghoshal, Gourab and Sinatra, Roberta}, + journal = {Scientific Reports}, + year = {2022}, + volume = {12}, + number = {6765}, + doi = {10.1038/s41598-022-10783-y} +} + +@article{folco2023dmn, + title = {Data-driven micromobility network planning for demand and safety}, + author = {Folco, Pietro and Gauvin, Laetitia and Tizzoni, Michele and Szell, Michael}, + journal = {Environment and Planning B: Urban Analytics and City Science}, + year = {2023}, + volume = {50}, + number = {8}, + pages = {2087--2102}, + doi = {10.1177/23998083221135611} +} \ No newline at end of file diff --git a/docs/conf.py b/docs/source/conf.py similarity index 52% rename from docs/conf.py rename to docs/source/conf.py index 120721e..ce0e6fb 100644 --- a/docs/conf.py +++ b/docs/source/conf.py @@ -7,7 +7,7 @@ # https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information project = "FixBikeNet" -copyright = "2026, Szell, Vybornova, Knepper" +copyright = "2026, FixBikeNet developers" author = "Szell, Vybornova, Knepper" # -- General configuration --------------------------------------------------- @@ -15,13 +15,16 @@ import os # noqa import sys # noqa +from pathlib import Path # noqa +from tomllib import load as toml_load # noqa -sys.path.insert(0, os.path.abspath("../")) +sys.path.insert(0, os.path.abspath("..")) import fixbikenet # noqa -# version = growbikenet.__version__ -version = "0.6.0" -release = version +# dynamically load version +with Path("../../pyproject.toml").open("rb") as f: + pyproject = toml_load(f) +version = release = pyproject["project"]["version"] # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom @@ -49,31 +52,61 @@ # path to bib file with references bibtex_bibfiles = ["_static/references.bib"] bibtex_reference_style = "author_year" +bibtex_default_style = 'plain' # -- Options for HTML output ------------------------------------------------- # https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output html_static_path = ["_static"] ### select html theme -# html_theme = 'alabaster' -html_theme = "pydata_sphinx_theme" +html_theme = "furo" html_theme_options = { - "github_url": "https://github.com/BikeNetKit/FixBikeNet", - "twitter_url": "notwitter.com", "pygment_light_style": "tango", "logo": { "image_light": "logo.png", "image_dark": "logo.png", }, + "light_css_variables": { + "color-brand-primary": "#096a51", + "color-brand-content": "#096a51", + "color-brand-visited": "#5b8b75", + }, + "dark_css_variables": { + "color-brand-primary": "#3cd71d", + "color-brand-content": "#3cd71d", + "color-brand-visited": "#5b8b75", + }, + "footer_icons": [ + { + "name": "Bluesky", + "url": "https://bsky.app/profile/bikenetkit.bsky.social", + "html": """ + + + + """, + "class": "", + }, + { + "name": "GitHub", + "url": "https://github.com/BikeNetKit/FixBikeNet", + "html": """ + + + + """, + "class": "", + }, + ], } # Generate the API documentation when building autosummary_generate = True autosummary_imported_members = True -numpydoc_show_class_members = True -class_members_toctree = True -numpydoc_show_inherited_class_members = True +numpydoc_show_class_members = False +class_members_toctree = False +numpydoc_show_inherited_class_members = False numpydoc_class_members_toctree = False numpydoc_use_plots = True autodoc_typehints = "none" @@ -90,9 +123,8 @@ .. note:: | This page was generated from `{{ docname }}`__. - | Interactive online version: :raw-html:`Binder badge` - __ https://github.com/BikeNetKit/FixBikeNet/blob/master/docs/{{ docname }} + __ https://github.com/BikeNetKit/FixBikeNet/blob/main/docs/source/{{ docname }} """ # noqa: E501 @@ -114,8 +146,8 @@ def find_source(): if domain != "py" or not info["module"]: return None try: - filename = "FixBikeNet/%s#L%d-L%d" % find_source() # noqa: UP031 + filename = "fixbikenet/%s#L%d-L%d" % find_source() # noqa: UP031 except Exception: filename = info["module"].replace(".", "/") + ".py" tag = "main" if "+" in release else ("v" + release) - return f"https://github.com/BikeNetKit/FixBikeNet/blob/{tag}/{filename}" \ No newline at end of file + return f"https://github.com/BikeNetKit/FixBikeNet/blob/{tag}/{filename}" diff --git a/docs/source/getting_started.rst b/docs/source/getting_started.rst new file mode 100644 index 0000000..42790b8 --- /dev/null +++ b/docs/source/getting_started.rst @@ -0,0 +1,38 @@ +Getting started +=============== + +Get Started in 4 Steps +---------------------- + +1. Install FixBikeNet by following the :doc:`installation` guide. + +2. Read the :ref:`introducing-fixbikenet` section below. + +3. To check that the installation worked, run ``python examples/mwe.py`` or the Jupyter :doc:`mwe`. + +4. Consult the :doc:`reference_user` for complete details on using the package. + +Finally, if you're not already familiar with `NetworkX`_ and `GeoPandas`_, make sure you read their user guides as FixBikeNet uses their data structures. + +.. _introducing-fixbikenet: + +Introducing FixBikeNet +----------------------- + +FixBikeNet is built on top of `OSMnx`_/`NetworkX`_ and `GeoPandas`_. It takes one mandatory parameter, the city name, which it passes via `Nominatim`_ to `OSMnx`_, to download a city's street network. FixBikeNet then runs the following operations: + +* TBA + + +To try it out, run the: + +.. toctree:: + :maxdepth: 1 + + Minimum working example + + +.. _GeoPandas: https://geopandas.org +.. _NetworkX: https://networkx.org +.. _OSMnx: https://osmnx.readthedocs.io +.. _Nominatim: https://nominatim.openstreetmap.org \ No newline at end of file diff --git a/docs/source/index.rst b/docs/source/index.rst new file mode 100644 index 0000000..2b000cd --- /dev/null +++ b/docs/source/index.rst @@ -0,0 +1,68 @@ +.. FixBikeNet documentation master file, created by + sphinx-quickstart on Thu Feb 12 15:01:19 2026. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +FixBikeNet |version| documentation +=================================== + +The Python package ``fixbikenet`` identifies the most important gaps to fill in a city's bicycle network. It is hosted on `Github `__, part of `BikeNetKit `__. + +The software downloads and pre-processes data from OpenStreetMap, identifies the gaps, saves the results, creates plots and videos. The source code builds on `the code from the +research paper `__ *Automated Detection of Missing Links in Bicycle Networks*. + + +Setup and use +------------- + +To set up FixBikeNet, see the :doc:`installation` page. +To use FixBikeNet, the :doc:`getting_started` page +is a good place to start, which also explains how the package works in detail. For technical documentation, consult the :doc:`reference_user`. + +.. Statement of need +.. ================= + +.. TBA + +How to cite +----------- + +If you use FixBikeNet in your research, please cite `the paper `__: + + A. Vybornova, T. Cunha, A. Gühnemann, M. Szell. Automated Detection of Missing Links in Bicycle Networks. Geographical Analysis 55(2), 239-267 (2023) + +Contributing +------------ + +If you want to contribute to the development of FixBikeNet, please read the +`CONTRIBUTING.md `__ +file. + +Supported by +------------ + +Development of BikeNetKit/FixBikeNet was supported by the Innovation Fund Denmark +and the EU HORIZON grant JUST STREETS. + +|Innovation Fund Denmark|    |European Union|   |JUST STREETS| + +.. |Innovation Fund Denmark| image:: _static/logo_innovationfund.png + :target: https://innovationsfonden.dk/en +.. |European Union| image:: _static/logo_eu.png + :target: https://commission.europa.eu/index_en +.. |JUST STREETS| image:: _static/logo_juststreets.png + :target: https://www.just-streets.eu/ + + +Documentation contents +---------------------- + +.. toctree:: + :maxdepth: 1 + + Home + installation + getting_started + reference_user + reference_developer + references diff --git a/docs/source/installation.rst b/docs/source/installation.rst new file mode 100644 index 0000000..e6fe9d5 --- /dev/null +++ b/docs/source/installation.rst @@ -0,0 +1,131 @@ +============= +Installation +============= + +The easy way +~~~~~~~~~~~~ + +The currently default way to install FixBikeNet is using pip: + +:: + + pip install fixbikenet + +If this does not work, follow the instructions below. + +Advanced installations +~~~~~~~~~~~~~~~~~~~~~~ + +The main step is to set up a virtual environment ``fbnenv`` in which to +install the package, and then to use or run the environment. Use either of the methods below. + +With conda/pip +^^^^^^^^^^^^^^ + +Installation with `conda `__ (or the faster `mamba `__). + +The conda-forge installation is not yet working. Therefore, you need to `clone the +repository `__ +and create the environment via the +``environment.yml`` file: + +:: + + conda env create --file environment.yml + conda activate fbnenv + pip install fixbikenet + + +With Pixi +^^^^^^^^^ + +Installation with `Pixi `__. + +First, `clone this +repository `__ +and create the environment via the +``environment.yml`` file: + +:: + + pixi init --import environment.yml + +At this point you can run fixbikenet in the environment, for example as +such: + +:: + + pixi run python examples/mwe.py + +.. + + | The first time you run code with Pixi, it might take a minute + longer, as Pixi resolves the environment’s dependencies only at + this point. + + +Run fixbikenet in Jupyter lab +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +After having set up the environment above, if you wish to run +fixbikenet via `JupyterLab `__, +follow the corresponding instructions below. + +With conda +^^^^^^^^^^ + +Using `conda `__ (or the faster `mamba `__), run: + +:: + + conda activate fbnenv + ipython kernel install --user --name=fbnenv + conda deactivate + jupyter lab + +Once Jupyter lab opens, switch the kernel (Kernel > Change Kernel > +fbnenv) + +With pip +^^^^^^^^ + +Using pip, run: + +:: + + pip install --user ipykernel + python -m ipykernel install --user --name=fbnenv + jupyter lab + +Once Jupyter lab opens, switch the kernel (Kernel > Change Kernel > +fbnenv) + + +With Pixi +^^^^^^^^^ + +Running fixbikenet in Jupter lab with +`Pixi `__ is straightforward: + +:: + + pixi run jupyter lab + +An instance of Jupyter lab is automatically going to open in your +browser after the environment is built. + +Development installation +~~~~~~~~~~~~~~~~~~~~~~~~ + +If you want to develop the project, `clone this +repository `__ +and create the environment via the +``environment-dev.yml`` file: + +:: + + pixi init --import environment-dev.yml + +The development environment is called ``fbnenvdev``. Make sure to also +read `our contribution +guidelines `__. diff --git a/docs/source/mwe.ipynb b/docs/source/mwe.ipynb new file mode 100644 index 0000000..1f0faa2 --- /dev/null +++ b/docs/source/mwe.ipynb @@ -0,0 +1,86 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "0", + "metadata": {}, + "source": [ + "## Minimum working example\n", + "This notebook runs a minimum working example with fixbikenet." + ] + }, + { + "cell_type": "markdown", + "id": "1", + "metadata": {}, + "source": [ + "### Import fixbikenet" + ] + }, + { + "cell_type": "markdown", + "id": "21330ccc-40a3-433a-8ce6-f547c47310ae", + "metadata": {}, + "source": [ + "The standard way of importing fixbikenet:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2", + "metadata": {}, + "outputs": [], + "source": [ + "import fixbikenet as fbn" + ] + }, + { + "cell_type": "markdown", + "id": "3", + "metadata": {}, + "source": [ + "### Run fixbikenet with example city Frederiksberg" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4", + "metadata": {}, + "outputs": [], + "source": [ + "gaps = fbn.fixbikenet(\"Frederiksberg municipality\")" + ] + }, + { + "cell_type": "markdown", + "id": "5", + "metadata": {}, + "source": [ + "data is saved in `.examples/` as `gaps.gpk`" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.12.13" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/docs/source/reference_developer.rst b/docs/source/reference_developer.rst new file mode 100644 index 0000000..9035245 --- /dev/null +++ b/docs/source/reference_developer.rst @@ -0,0 +1,19 @@ +Developer reference +=================== + +This is the complete developer reference for the FixBikeNet package. If you are looking for an introduction to FixBikeNet, read the :doc:`getting_started` guide. + +fixbikenet.fixbikenet +----------------------- + +.. automodule:: fixbikenet.fixbikenet + :members: + +fixbikenet.functions +--------------------- + +.. automodule:: fixbikenet.functions + :members: + :private-members: + + \ No newline at end of file diff --git a/docs/source/reference_user.rst b/docs/source/reference_user.rst new file mode 100644 index 0000000..1fadca0 --- /dev/null +++ b/docs/source/reference_user.rst @@ -0,0 +1,9 @@ +User reference +============== + +This is the user reference for the FixBikeNet package. If you are looking for an introduction to FixBikeNet, read the :doc:`getting_started` guide. + +The standard way to import the FixBikeNet package is via ``import fixbikenet as fbn``. The main ``fixbikenet()`` function below is then called via ``fbn.fixbikenet()``, see the :doc:`mwe`. + +.. automodule:: fixbikenet.fixbikenet + :members: \ No newline at end of file diff --git a/docs/source/references.rst b/docs/source/references.rst new file mode 100644 index 0000000..6cd4a15 --- /dev/null +++ b/docs/source/references.rst @@ -0,0 +1,5 @@ +References +========== + +.. bibliography:: _static/references.bib + :cited: \ No newline at end of file diff --git a/environment-dev.yml b/environment-dev.yml index 7db88c4..983925e 100644 --- a/environment-dev.yml +++ b/environment-dev.yml @@ -4,9 +4,30 @@ channels: dependencies: - python=3.12 - jupyter + - jupyterlab + - ipywidgets + - ipykernel + - matplotlib - geopandas>=0.14 - osmnx>=1.9.4 - pip - pytest - pixi-pycharm - - pre-commit \ No newline at end of file + - pre-commit + - sphinx + - numpydoc + - myst-nb + - sphinx-book-theme + - nbsphinx + - myst-parser + - ipython + - pip: + # not available via conda-forge: + - opencv-python + - pre-commit + - sphinxcontrib-bibtex + - sphinx-copybutton + - sphinx-gallery + - python-slugify + - fixbikenet + - furo \ No newline at end of file diff --git a/examples/mwe.ipynb b/examples/mwe.ipynb index cf8edb9..1f0faa2 100644 --- a/examples/mwe.ipynb +++ b/examples/mwe.ipynb @@ -6,7 +6,7 @@ "metadata": {}, "source": [ "## Minimum working example\n", - "This notebook runs a minimum working example with fixbikenet" + "This notebook runs a minimum working example with fixbikenet." ] }, { @@ -17,6 +17,14 @@ "### Import fixbikenet" ] }, + { + "cell_type": "markdown", + "id": "21330ccc-40a3-433a-8ce6-f547c47310ae", + "metadata": {}, + "source": [ + "The standard way of importing fixbikenet:" + ] + }, { "cell_type": "code", "execution_count": null, @@ -42,9 +50,7 @@ "metadata": {}, "outputs": [], "source": [ - "gaps = fbn.fixbikenet(\n", - " city_name=\"Frederiksberg municipality\",\n", - ")" + "gaps = fbn.fixbikenet(\"Frederiksberg municipality\")" ] }, { diff --git a/pyproject.toml b/pyproject.toml index ab0ed9d..38c25d4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -13,9 +13,10 @@ authors = [ maintainers = [{ name = "Manuel Knepper", email = "manuel.knepper@gmx.net" }] license = "AGPL-3.0-or-later" readme = "README.md" -description = "Python package to detect gaps in developed bicycle networks" +description = "BikeNetKit Python package to detect gaps in developed bicycle networks" keywords = ["Bicycle network planning", "Networks", "OpenStreetMap", "Urban Planning", "Urban Mobility"] classifiers = [ + "Development Status :: 3 - Alpha", "Intended Audience :: Developers", "Intended Audience :: Science/Research", "Operating System :: OS Independent", @@ -45,6 +46,9 @@ Issues = "https://github.com/BikeNetKit/FixBikeNet/issues" test = ["pytest"] doc = ["sphinx", "momepy"] +[tool.ruff.lint.extend-per-file-ignores] +"__init__.py" = ["F401"] # "Imported but unused: happens with packages + [tool.setuptools.packages.find] exclude = [ "examples*",