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
-[](https://github.com/astral-sh/ruff)
-[](https://github.com/prettier/prettier)
-[](https://github.com/pre-commit/pre-commit)
-[](https://github.com/BikeNetKit/FixBikeNet/actions/workflows/docs.yml)
+[](https://bikenetkit.github.io/FixBikeNet/)
[](https://github.com/BikeNetKit/FixBikeNet/actions/workflows/test.yml)
+[](https://pypi.org/project/FixBikeNet/)
+[](https://github.com/astral-sh/ruff)
+
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).
+[](https://innovationsfonden.dk/en) [](https://commission.europa.eu/index_en) [](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:``
- __ 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*",