roadstyle 0.2.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- roadstyle-0.2.0/LICENSE +21 -0
- roadstyle-0.2.0/PKG-INFO +406 -0
- roadstyle-0.2.0/README.md +348 -0
- roadstyle-0.2.0/pyproject.toml +86 -0
- roadstyle-0.2.0/setup.cfg +4 -0
- roadstyle-0.2.0/src/roadstyle/__init__.py +124 -0
- roadstyle-0.2.0/src/roadstyle/_settings.py +182 -0
- roadstyle-0.2.0/src/roadstyle/basemaps.py +113 -0
- roadstyle-0.2.0/src/roadstyle/cli.py +169 -0
- roadstyle-0.2.0/src/roadstyle/colors.py +117 -0
- roadstyle-0.2.0/src/roadstyle/config.py +99 -0
- roadstyle-0.2.0/src/roadstyle/controls.py +126 -0
- roadstyle-0.2.0/src/roadstyle/data/defaults.json +629 -0
- roadstyle-0.2.0/src/roadstyle/edges.py +295 -0
- roadstyle-0.2.0/src/roadstyle/emit.py +247 -0
- roadstyle-0.2.0/src/roadstyle/filters.py +54 -0
- roadstyle-0.2.0/src/roadstyle/interactive.py +186 -0
- roadstyle-0.2.0/src/roadstyle/legend.py +110 -0
- roadstyle-0.2.0/src/roadstyle/overlays.py +82 -0
- roadstyle-0.2.0/src/roadstyle/palettes.py +172 -0
- roadstyle-0.2.0/src/roadstyle/py.typed +0 -0
- roadstyle-0.2.0/src/roadstyle/render.py +141 -0
- roadstyle-0.2.0/src/roadstyle/render_folium.py +116 -0
- roadstyle-0.2.0/src/roadstyle/render_lonboard.py +115 -0
- roadstyle-0.2.0/src/roadstyle/render_web.py +1277 -0
- roadstyle-0.2.0/src/roadstyle/snapshot.py +102 -0
- roadstyle-0.2.0/src/roadstyle/static/roadstyle.css +147 -0
- roadstyle-0.2.0/src/roadstyle/static/roadstyle.js +608 -0
- roadstyle-0.2.0/src/roadstyle/static/web_template.html +594 -0
- roadstyle-0.2.0/src/roadstyle/style.py +96 -0
- roadstyle-0.2.0/src/roadstyle/stylers.py +472 -0
- roadstyle-0.2.0/src/roadstyle/tiles.py +200 -0
- roadstyle-0.2.0/src/roadstyle/validate.py +62 -0
- roadstyle-0.2.0/src/roadstyle/vendor/maplibre-gl.css +1 -0
- roadstyle-0.2.0/src/roadstyle/vendor/maplibre-gl.js +59 -0
- roadstyle-0.2.0/src/roadstyle/vendor/pmtiles.js +1738 -0
- roadstyle-0.2.0/src/roadstyle.egg-info/PKG-INFO +406 -0
- roadstyle-0.2.0/src/roadstyle.egg-info/SOURCES.txt +54 -0
- roadstyle-0.2.0/src/roadstyle.egg-info/dependency_links.txt +1 -0
- roadstyle-0.2.0/src/roadstyle.egg-info/entry_points.txt +2 -0
- roadstyle-0.2.0/src/roadstyle.egg-info/requires.txt +40 -0
- roadstyle-0.2.0/src/roadstyle.egg-info/top_level.txt +1 -0
- roadstyle-0.2.0/tests/test_cli.py +69 -0
- roadstyle-0.2.0/tests/test_color_table.py +59 -0
- roadstyle-0.2.0/tests/test_edges.py +143 -0
- roadstyle-0.2.0/tests/test_emit.py +225 -0
- roadstyle-0.2.0/tests/test_legend.py +62 -0
- roadstyle-0.2.0/tests/test_palette_io.py +65 -0
- roadstyle-0.2.0/tests/test_render.py +69 -0
- roadstyle-0.2.0/tests/test_render_datadriven.py +90 -0
- roadstyle-0.2.0/tests/test_render_web.py +687 -0
- roadstyle-0.2.0/tests/test_settings_overrides.py +121 -0
- roadstyle-0.2.0/tests/test_style.py +88 -0
- roadstyle-0.2.0/tests/test_stylers.py +82 -0
- roadstyle-0.2.0/tests/test_tiles.py +148 -0
- roadstyle-0.2.0/tests/test_web_smoke.py +103 -0
roadstyle-0.2.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Kaveh
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
roadstyle-0.2.0/PKG-INFO
ADDED
|
@@ -0,0 +1,406 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: roadstyle
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: Opinionated OSM-theme road/edge map styling for folium, lonboard & the web (data-driven palettes, casing, themes)
|
|
5
|
+
Author: Kaveh
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/Khoshkhah/roadstyle
|
|
8
|
+
Project-URL: Documentation, https://khoshkhah.github.io/roadstyle/
|
|
9
|
+
Project-URL: Source, https://github.com/Khoshkhah/roadstyle
|
|
10
|
+
Project-URL: Changelog, https://github.com/Khoshkhah/roadstyle/blob/main/CHANGELOG.md
|
|
11
|
+
Keywords: openstreetmap,osm,roads,cartography,map,visualization,folium,lonboard,geopandas,leaflet,maplibre
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Intended Audience :: Science/Research
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Operating System :: OS Independent
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Topic :: Scientific/Engineering :: GIS
|
|
21
|
+
Classifier: Topic :: Scientific/Engineering :: Visualization
|
|
22
|
+
Requires-Python: >=3.10
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
|
+
License-File: LICENSE
|
|
25
|
+
Requires-Dist: geopandas
|
|
26
|
+
Requires-Dist: shapely
|
|
27
|
+
Requires-Dist: folium
|
|
28
|
+
Requires-Dist: branca
|
|
29
|
+
Provides-Extra: numeric
|
|
30
|
+
Requires-Dist: mapclassify; extra == "numeric"
|
|
31
|
+
Requires-Dist: matplotlib; extra == "numeric"
|
|
32
|
+
Provides-Extra: basemaps
|
|
33
|
+
Requires-Dist: xyzservices; extra == "basemaps"
|
|
34
|
+
Provides-Extra: lonboard
|
|
35
|
+
Requires-Dist: lonboard; extra == "lonboard"
|
|
36
|
+
Provides-Extra: duckdb
|
|
37
|
+
Requires-Dist: duckdb; extra == "duckdb"
|
|
38
|
+
Provides-Extra: arrow
|
|
39
|
+
Requires-Dist: pyarrow; extra == "arrow"
|
|
40
|
+
Provides-Extra: tiles
|
|
41
|
+
Requires-Dist: mapbox-vector-tile; extra == "tiles"
|
|
42
|
+
Requires-Dist: pmtiles; extra == "tiles"
|
|
43
|
+
Provides-Extra: docs
|
|
44
|
+
Requires-Dist: mkdocs-material; extra == "docs"
|
|
45
|
+
Provides-Extra: dev
|
|
46
|
+
Requires-Dist: pytest; extra == "dev"
|
|
47
|
+
Requires-Dist: ruff; extra == "dev"
|
|
48
|
+
Requires-Dist: mypy; extra == "dev"
|
|
49
|
+
Requires-Dist: lonboard; extra == "dev"
|
|
50
|
+
Requires-Dist: mapclassify; extra == "dev"
|
|
51
|
+
Requires-Dist: matplotlib; extra == "dev"
|
|
52
|
+
Requires-Dist: xyzservices; extra == "dev"
|
|
53
|
+
Requires-Dist: duckdb; extra == "dev"
|
|
54
|
+
Requires-Dist: pyarrow; extra == "dev"
|
|
55
|
+
Requires-Dist: mapbox-vector-tile; extra == "dev"
|
|
56
|
+
Requires-Dist: pmtiles; extra == "dev"
|
|
57
|
+
Dynamic: license-file
|
|
58
|
+
|
|
59
|
+
# roadstyle
|
|
60
|
+
|
|
61
|
+
[](https://github.com/Khoshkhah/roadstyle/actions/workflows/test.yml)
|
|
62
|
+
[](LICENSE)
|
|
63
|
+
[](pyproject.toml)
|
|
64
|
+
|
|
65
|
+
Turn a GeoDataFrame of road edges into a **styled, interactive, self-contained map** — proper
|
|
66
|
+
road cartography (the casing + fill "geometry sandwich", per-zoom widths, street names, one-way
|
|
67
|
+
arrows, tunnel/bridge grade separation, optional 3D bridge decks) in one offline HTML file, with
|
|
68
|
+
a scriptable JavaScript API.
|
|
69
|
+
|
|
70
|
+

|
|
71
|
+
|
|
72
|
+
**Contents:**
|
|
73
|
+
[Features](#features) ·
|
|
74
|
+
[Installation](#installation) ·
|
|
75
|
+
[Quickstart](#quickstart) ·
|
|
76
|
+
[The studio (no code)](#the-studio--the-library-behind-knobs-no-code) ·
|
|
77
|
+
[Rendering parameters](#rendering-parameters) ·
|
|
78
|
+
[Data contract](#data-contract--which-column-powers-what) ·
|
|
79
|
+
[Recipes](#recipes) ·
|
|
80
|
+
[JavaScript API](#drive-the-map-from-javascript) ·
|
|
81
|
+
[Settings](#settings--one-defaults-file-your-overrides-on-top) ·
|
|
82
|
+
[Command line](#command-line) ·
|
|
83
|
+
[Documentation](#documentation)
|
|
84
|
+
|
|
85
|
+
## Features
|
|
86
|
+
|
|
87
|
+
- **Real road cartography** — casing + fill sandwich, importance-ordered junctions, per-zoom
|
|
88
|
+
widths (openstreetmap-carto model), two-way lanes, curved street names, one-way arrows.
|
|
89
|
+
- **Grade separation** — tunnels faded + dashed underneath, bridges on decks on top (stacked
|
|
90
|
+
structures ordered by their OSM `layer`), and an optional **3D view** with extruded bridge decks.
|
|
91
|
+
- **One offline file** — MapLibre and the data are bundled into the saved HTML; it opens by
|
|
92
|
+
double-click, no server, no internet (with the `blank` basemap: zero network requests).
|
|
93
|
+
- **Data-driven styling** — colour/width by any column (categorical or numeric ramps), per-edge
|
|
94
|
+
colour tables, and multiple colour layers switchable client-side.
|
|
95
|
+
- **Big networks** — `tiles=True` packs the roads as an embedded vector tileset (PMTiles):
|
|
96
|
+
~10⁵-edge maps open in seconds and stay responsive, still one offline file.
|
|
97
|
+
- **A JavaScript API** — every control is scriptable (`rsQuery`, `rsFilter`, `rsColor`,
|
|
98
|
+
`rsSelect`, …) with `rs:*` events, so the saved map can power your own dashboard.
|
|
99
|
+
- **Three backends** — `web` (MapLibre, the flagship), `folium` (Leaflet, legends), `lonboard`
|
|
100
|
+
(GPU, millions of edges).
|
|
101
|
+
|
|
102
|
+
## Installation
|
|
103
|
+
|
|
104
|
+
Python ≥ 3.10. Core dependencies (`geopandas`, `shapely`, `folium`, `branca`) install
|
|
105
|
+
automatically.
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
pip install roadstyle # from PyPI (v0.2.0+)
|
|
109
|
+
|
|
110
|
+
# or the latest development state straight from GitHub:
|
|
111
|
+
pip install "roadstyle @ git+https://github.com/Khoshkhah/roadstyle.git"
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
Optional features are extras — install only what you need:
|
|
115
|
+
|
|
116
|
+
| Extra | Enables | Pulls in |
|
|
117
|
+
|---|---|---|
|
|
118
|
+
| `numeric` | continuous colour ramps + classification (`color_by` on numbers) | mapclassify, matplotlib |
|
|
119
|
+
| `tiles` | `tiles=True` — embedded vector tiles for big networks | mapbox-vector-tile, pmtiles |
|
|
120
|
+
| `lonboard` | the GPU backend for very large edge sets | lonboard |
|
|
121
|
+
| `duckdb` | `from_duckdb()` — read edges straight from DuckDB | duckdb |
|
|
122
|
+
| `arrow` | read edges from a pyarrow Table | pyarrow |
|
|
123
|
+
| `basemaps` | any XYZ provider from the xyzservices registry | xyzservices |
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
pip install "roadstyle[numeric,tiles]"
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
**Development install** (clone + editable + test tools):
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
git clone https://github.com/Khoshkhah/roadstyle.git && cd roadstyle
|
|
133
|
+
pip install -e ".[dev]"
|
|
134
|
+
# or with conda: conda env create -f environment.yml && conda activate roadstyle && pip install -e ".[dev]"
|
|
135
|
+
pytest # 160 tests; browser tests need `pip install playwright`
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
**Uninstall:** `pip uninstall roadstyle`. Your personal settings overrides
|
|
139
|
+
(`~/.config/roadstyle/roadstyle.json`, project-local `roadstyle.json`) are your files — pip
|
|
140
|
+
leaves them in place; delete them yourself if you want a clean slate.
|
|
141
|
+
|
|
142
|
+
## Quickstart
|
|
143
|
+
|
|
144
|
+
```python
|
|
145
|
+
import geopandas as gpd
|
|
146
|
+
import roadstyle as rs
|
|
147
|
+
|
|
148
|
+
edges = gpd.read_file("edges.gpkg") # any CRS; needs a `highway` class column
|
|
149
|
+
|
|
150
|
+
rs.render_edges(edges).save("map.html") # done — open map.html
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
That one line gives you the full treatment: per-zoom widths, two-way lanes, arrows, street
|
|
154
|
+
names, hover/select with popups, a base-map switcher, a class filter panel, grade separation.
|
|
155
|
+
Common variations:
|
|
156
|
+
|
|
157
|
+
```python
|
|
158
|
+
rs.render_edges(edges, basemap="dark_matter", view_3d=True).save("map3d.html") # dark + 3D bridges
|
|
159
|
+
rs.render_edges(edges, palette="carto", basemap="positron").save("carto.html") # the classic OSM look
|
|
160
|
+
rs.render_edges(edges, include=["motorway", "trunk", "primary"]).save("major.html")
|
|
161
|
+
rs.render_edges(edges, color_by="aadt", cmap="viridis").save("traffic.html") # colour by your data
|
|
162
|
+
rs.render_edges(edges, tiles=True).save("big.html") # 10⁵-edge networks
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
Palettes: **`highsat`** (high-saturation, maximum legibility), **`carto`** (the muted
|
|
166
|
+
openstreetmap-carto look), **`mono`** (grayscale — quiet backdrop for data overlays).
|
|
167
|
+
|
|
168
|
+
## The studio — the library behind knobs, no code
|
|
169
|
+
|
|
170
|
+
The gentlest way in. The studio is a small Streamlit app bundled in the repo (not part of the
|
|
171
|
+
pip package):
|
|
172
|
+
|
|
173
|
+
```bash
|
|
174
|
+
git clone https://github.com/Khoshkhah/roadstyle.git && cd roadstyle
|
|
175
|
+
pip install roadstyle streamlit
|
|
176
|
+
streamlit run ui/studio/app.py
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+

|
|
180
|
+
|
|
181
|
+
Two pages, same idea — every knob updates the live map **and** the exact Python code that
|
|
182
|
+
reproduces it:
|
|
183
|
+
|
|
184
|
+
- **Map** — upload a road file (`.gpkg` / `.geojson`) or pick a bundled Södermalm sample, then
|
|
185
|
+
click through palette, base map, 3D, vector tiles, colour-by-data, class filter, minzoom,
|
|
186
|
+
labels/arrows, popups and overlays. Copy the generated `render_edges(...)` code out, or
|
|
187
|
+
download the self-contained `map.html`.
|
|
188
|
+
- **Dashboard** — the same knobs, but the product is a **sidebar dashboard** (query box, verb
|
|
189
|
+
buttons, results table, detail panel) built on the JavaScript API. Preview it live, download
|
|
190
|
+
`dashboard.html`.
|
|
191
|
+
|
|
192
|
+
## Rendering parameters
|
|
193
|
+
|
|
194
|
+
The keywords of `rs.render_edges(gdf, ...)` — the ones you'll actually reach for. Full
|
|
195
|
+
reference with every type and edge case: [docs/parameters.md](docs/parameters.md).
|
|
196
|
+
|
|
197
|
+
**Core**
|
|
198
|
+
|
|
199
|
+
| Parameter | Default | What it does |
|
|
200
|
+
|---|---|---|
|
|
201
|
+
| `backend` | `"web"` | `"web"` (MapLibre, the flagship) / `"folium"` (Leaflet + legends) / `"lonboard"` (GPU) |
|
|
202
|
+
| `palette` | `"highsat"` | Class colour palette: `"highsat"` / `"carto"` / `"mono"`, or your own |
|
|
203
|
+
| `basemap` | `"voyager"` | Background map: `voyager`, `positron`, `dark_matter`, `osm`, `satellite`, `blank`, `blank_dark` |
|
|
204
|
+
| `basemaps` | all built-ins | The set offered in the in-map base-layer dropdown |
|
|
205
|
+
| `name` | `"roadstyle"` | Page / layer title |
|
|
206
|
+
| `settings` | `None` | Per-call settings override (dict or path) — see [Settings](#settings--one-defaults-file-your-overrides-on-top) |
|
|
207
|
+
|
|
208
|
+
**Filtering**
|
|
209
|
+
|
|
210
|
+
| Parameter | Default | What it does |
|
|
211
|
+
|---|---|---|
|
|
212
|
+
| `include` / `exclude` | `None` | Keep / drop road classes (`include=["motorway","primary"]`); `_link` variants follow automatically |
|
|
213
|
+
| `filter_col` | `None` | Let the filter panel list a different column than the one that drives styling |
|
|
214
|
+
| `minzoom` | `None` (off) | Hide minor classes when zoomed out: `True` for the built-in table, or a `{class: zoom}` dict. Applies to the vector tiles too |
|
|
215
|
+
|
|
216
|
+
**Colour by data**
|
|
217
|
+
|
|
218
|
+
| Parameter | Default | What it does |
|
|
219
|
+
|---|---|---|
|
|
220
|
+
| `color_by` | `None` | Colour by a column instead of road class |
|
|
221
|
+
| `colors` | `None` | Categorical `{value: "#hex"}` map, or `"self"` to use the column's value as the literal colour |
|
|
222
|
+
| `cmap` / `vmin` / `vmax` | `None` | Numeric colour ramp (`"viridis"`, …) and its value range |
|
|
223
|
+
| `width_by` | `None` | `(min_px, max_px)` — scale line width with the numeric value |
|
|
224
|
+
| `color_table` | `None` | Per-edge colours: `{edge_id: "#hex"}` dict / Series / DataFrame (gray fallback, class widths kept) |
|
|
225
|
+
| `color_options` | `None` | Bake **several** colour layers + a client-side *Colour by* dropdown: `{"Traffic": {"color_by": "aadt", "cmap": "viridis"}, ...}` |
|
|
226
|
+
|
|
227
|
+
**Camera & 3D** (web backend)
|
|
228
|
+
|
|
229
|
+
| Parameter | Default | What it does |
|
|
230
|
+
|---|---|---|
|
|
231
|
+
| `view_3d` | `False` | Tilted camera + extruded, ramped, cased 3D bridge decks + an on-map 2D/3D toggle |
|
|
232
|
+
| `pitch` / `bearing` | settings | Starting camera tilt / rotation |
|
|
233
|
+
|
|
234
|
+
**UI toggles** (web backend)
|
|
235
|
+
|
|
236
|
+
| Parameter | Default | What it does |
|
|
237
|
+
|---|---|---|
|
|
238
|
+
| `arrows` | `True` | One-way direction chevrons |
|
|
239
|
+
| `labels` | `True` | Curved street-name labels |
|
|
240
|
+
| `filter_control` | `True` | The collapsible road-class filter panel (doubles as a colour legend) |
|
|
241
|
+
| `basemap_switcher` | `True` | The base-layer dropdown |
|
|
242
|
+
| `road_popup` | `True` | Click popup: `True` (curated fields) / `[fields]` / `"all"` / `"panel"` (docked read-out) / `False` |
|
|
243
|
+
| `tooltip` | `None` (off) | Hover tooltip fields (list of columns) |
|
|
244
|
+
| `hover_color` / `select_color` | violet | Highlight colours for hovered / selected roads |
|
|
245
|
+
|
|
246
|
+
**Extra content** (web backend)
|
|
247
|
+
|
|
248
|
+
| Parameter | Default | What it does |
|
|
249
|
+
|---|---|---|
|
|
250
|
+
| `overlays` | `None` | Your own layers (`Overlay(...)`) — zones under the roads, POIs on top, clickable, with a Layers toggle |
|
|
251
|
+
| `boundary` | `None` | Dashed outline of the clip area, drawn on top |
|
|
252
|
+
| `selected` | `None` | Pre-highlighted edges (folium backend) |
|
|
253
|
+
|
|
254
|
+
**Output & scale**
|
|
255
|
+
|
|
256
|
+
| Parameter | Default | What it does |
|
|
257
|
+
|---|---|---|
|
|
258
|
+
| `compress` | `True` | Gzip the inlined data (3–4× smaller files; `compress=False` for plain JSON) |
|
|
259
|
+
| `tiles` | `False` | Embedded-PMTiles vector tileset — for ~10⁵-edge networks (needs the `tiles` extra) |
|
|
260
|
+
|
|
261
|
+
**Column mapping**
|
|
262
|
+
|
|
263
|
+
| Parameter | Default | What it does |
|
|
264
|
+
|---|---|---|
|
|
265
|
+
| `highway_col` | `"highway"` | The road-class column that drives styling |
|
|
266
|
+
| `tunnel_col` / `bridge_col` / `layer_col` | `"tunnel"` / `"bridge"` / `"layer"` | Grade-separation columns |
|
|
267
|
+
|
|
268
|
+
Everything *stylistic* — the actual colours, widths, casing, label/arrow cosmetics, camera
|
|
269
|
+
defaults, bridge-deck geometry — is deliberately **not** a keyword but a
|
|
270
|
+
[setting](#settings--one-defaults-file-your-overrides-on-top).
|
|
271
|
+
|
|
272
|
+
## Data contract — which column powers what
|
|
273
|
+
|
|
274
|
+
Only two things are required; every other column lights up a feature when present and is
|
|
275
|
+
skipped when absent:
|
|
276
|
+
|
|
277
|
+
| Column | Values | Powers |
|
|
278
|
+
|---|---|---|
|
|
279
|
+
| *geometry* | LineString (any CRS) | **required** — the edges themselves |
|
|
280
|
+
| `highway` | OSM class (`motorway`…`service`) | **required** — colour, width, casing, draw order |
|
|
281
|
+
| `name` | text | street-name labels + the popup title |
|
|
282
|
+
| `oneway` | `True`/`False` / `yes`/`no` | direction arrows (without it, one-way is inferred from reverse-geometry twins) |
|
|
283
|
+
| `bridge` / `tunnel` | truthy | grade separation: tunnels below, bridges on decks above, 3D decks in `view_3d` |
|
|
284
|
+
| `layer` | int | stacking order of bridges/tunnels; negative → below ground even without `tunnel` |
|
|
285
|
+
| `edge_id` | id (64-bit safe) | popups + click-to-copy; ids > 2⁵³ are kept exact as strings |
|
|
286
|
+
| anything else | anything | shown in the click popup / hover tooltip, queryable from JavaScript |
|
|
287
|
+
|
|
288
|
+
Networks exported by [duckOSM](https://github.com/Khoshkhah/duckOSM) (`duckosm export-gis`)
|
|
289
|
+
carry exactly this column set.
|
|
290
|
+
|
|
291
|
+
## Recipes
|
|
292
|
+
|
|
293
|
+
Each of these is one call — details behind the links.
|
|
294
|
+
|
|
295
|
+
```python
|
|
296
|
+
# colour each edge from your own table (cluster / route / metric per edge)
|
|
297
|
+
rs.render_edges(edges, color_table={"4897…": "#e6194B", "5193…": "#3cb44b"})
|
|
298
|
+
|
|
299
|
+
# several colour layers in one map, switchable client-side (no re-render)
|
|
300
|
+
rs.render_edges(edges, palette="mono", color_options={
|
|
301
|
+
"Road class": {},
|
|
302
|
+
"Traffic": {"color_by": "aadt", "cmap": "viridis"},
|
|
303
|
+
"Speed": {"color_by": "maxspeed_kmh", "cmap": "magma"}})
|
|
304
|
+
|
|
305
|
+
# your own layers under/over the roads
|
|
306
|
+
rs.render_edges(edges, overlays=[
|
|
307
|
+
rs.Overlay(zones, placement="under", color="#2d6cdf", opacity=0.25, label="Zones",
|
|
308
|
+
popup=["taz_id", "population"]),
|
|
309
|
+
rs.Overlay(sensors, placement="over", color="#ffd166", radius=6, label="Sensors")])
|
|
310
|
+
|
|
311
|
+
# your own tile server as a base map
|
|
312
|
+
rs.register_basemap(rs.Basemap(key="lm", label="Lantmäteriet",
|
|
313
|
+
url="https://tiles.example.se/{z}/{x}/{y}.png", attr="© LM"))
|
|
314
|
+
|
|
315
|
+
# a static PNG for a paper, through a real headless browser (pip install playwright)
|
|
316
|
+
rs.snapshot(rs.render_edges(edges, view_3d=True), "fig.png",
|
|
317
|
+
center=(18.076, 59.303), zoom=16, pitch=60)
|
|
318
|
+
|
|
319
|
+
# roads straight from DuckDB
|
|
320
|
+
edges = rs.from_duckdb(con, "SELECT edge_id, highway, name, ST_AsWKB(geom) AS geometry FROM edges")
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
More: [the gallery](docs/gallery.md) — one screenshot + recipe per look.
|
|
324
|
+
|
|
325
|
+
## Drive the map from JavaScript
|
|
326
|
+
|
|
327
|
+
Every in-map control is a thin UI over a `window.rs*` function, and the baked features are a
|
|
328
|
+
queryable table — so a saved map can power your own dashboard with plain HTML:
|
|
329
|
+
|
|
330
|
+
```js
|
|
331
|
+
const ids = rsQuery(p => p.lanes >= 2 && p.maxspeed_kmh > 30); // WHERE clause → id set
|
|
332
|
+
rsFilter(ids); // show only these rsFilter(null) resets
|
|
333
|
+
rsColor(ids, "#ff00aa"); // paint them one colour rsColor(null) resets
|
|
334
|
+
rsHighlight(ids); // selection glow
|
|
335
|
+
rsGetProps(ids); // the rows behind the ids — table-ready
|
|
336
|
+
rsFocus(ids); // fly the camera to fit them
|
|
337
|
+
rsSelect(id); // select + popup, like a click
|
|
338
|
+
|
|
339
|
+
rsSetBasemap("dark_matter"); rsSetClasses(["primary","secondary"]);
|
|
340
|
+
rsSetColorField("Traffic"); rsSetOverlay("Zones", false); rsSetView3D(true);
|
|
341
|
+
|
|
342
|
+
document.addEventListener("rs:select", e => showSidebar(e.detail.properties));
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
Everything works the same on overlays (pass the overlay's label as the last argument) and on
|
|
346
|
+
tiled maps. Full API table: [docs/web-backend.md](docs/web-backend.md#the-javascript-api-windowrs).
|
|
347
|
+
Ready-made scaffolding: [`ui/`](ui/) — `python ui/dashboard/build.py your_edges.gpkg [--tiles]`
|
|
348
|
+
builds a complete sidebar dashboard on this API.
|
|
349
|
+
|
|
350
|
+
## Settings — one defaults file, your overrides on top
|
|
351
|
+
|
|
352
|
+
EVERY styling default — palettes, opacities, casing, the width/draw-order model, base map,
|
|
353
|
+
camera, labels, arrows, bridge decks — ships in one file, `roadstyle/data/defaults.json`. You
|
|
354
|
+
never edit it; you state only what changes, at any of five levels (later wins):
|
|
355
|
+
|
|
356
|
+
1. `~/.config/roadstyle/roadstyle.json` — personal defaults
|
|
357
|
+
2. `./roadstyle.json` — project-local
|
|
358
|
+
3. `$ROADSTYLE_CONFIG=/path/to/file.json` — per run
|
|
359
|
+
4. `rs.use_settings({...})` — from code, applies immediately
|
|
360
|
+
5. `render_edges(..., settings={...})` — this one call only
|
|
361
|
+
|
|
362
|
+
```jsonc
|
|
363
|
+
{
|
|
364
|
+
"palettes": { "highsat": { "service": { "fill": "#E0E0E0" } } }, // retint one class
|
|
365
|
+
"config": { "basemap": "dark_matter", "labels": { "color": "#8899aa" } },
|
|
366
|
+
"roads": { "z_order": { "service": 5 }, "width": { "secondary": { "18": 14 } } }
|
|
367
|
+
}
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
Details: [docs/palettes.md](docs/palettes.md).
|
|
371
|
+
|
|
372
|
+
## Command line
|
|
373
|
+
|
|
374
|
+
No Python required — point the `roadstyle` command at any road file:
|
|
375
|
+
|
|
376
|
+
```bash
|
|
377
|
+
roadstyle edges.gpkg -o map.html --basemap dark_matter # styled interactive map
|
|
378
|
+
roadstyle edges.gpkg --view-3d --tiles # 3D + embedded vector tiles
|
|
379
|
+
roadstyle edges.gpkg --include motorway trunk primary
|
|
380
|
+
roadstyle edges.gpkg --color-by aadt --cmap viridis --width-by 1 6
|
|
381
|
+
roadstyle edges.gpkg -f spec -o map_data.json # JSON spec for your own frontend
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
Every flag mirrors a `render_edges` keyword; `roadstyle --help` lists them all.
|
|
385
|
+
|
|
386
|
+
## Documentation
|
|
387
|
+
|
|
388
|
+
| | |
|
|
389
|
+
|---|---|
|
|
390
|
+
| [Gallery](docs/gallery.md) | one screenshot + recipe per look |
|
|
391
|
+
| [Parameter reference](docs/parameters.md) | every keyword, type, and default |
|
|
392
|
+
| [Web backend](docs/web-backend.md) | grade separation, 3D, vector tiles, colour options, the full JS API |
|
|
393
|
+
| [Choosing an engine](docs/engines.md) | web vs folium vs lonboard, data-size guidance |
|
|
394
|
+
| [Palettes & settings](docs/palettes.md) | the built-in palettes and the override system |
|
|
395
|
+
| [When to use roadstyle](docs/comparison.md) | vs `.explore()`, prettymaps, kepler.gl, raw MapLibre |
|
|
396
|
+
| [Notebooks](notebooks/) | a runnable manual, one topic per notebook |
|
|
397
|
+
| [UI templates](ui/) | the dashboard scaffolding + the studio |
|
|
398
|
+
|
|
399
|
+
Full MkDocs site: [khoshkhah.github.io/roadstyle](https://khoshkhah.github.io/roadstyle/)
|
|
400
|
+
(`mkdocs serve` locally).
|
|
401
|
+
|
|
402
|
+
## License
|
|
403
|
+
|
|
404
|
+
[MIT](LICENSE). Base-map tiles are third-party services (CARTO, OSM, Esri) with their own
|
|
405
|
+
attribution and terms; the styling spec is transcribed from the cartographic design docs in the
|
|
406
|
+
osm-traffic-enrichment project.
|