Switch map tiles from CartoDB positron to OpenStreetMap (no API key)

CartoDB's positron basemap now renders an "API KEY REQUIRED" watermark.
Use tiles="OpenStreetMap" via a new MAP_TILES constant instead.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-07 19:08:09 +02:00
parent caecc60c7b
commit e3bbd4d264
6 changed files with 43 additions and 11 deletions
+5 -1
View File
@@ -58,6 +58,10 @@ GEOCODE_REGIONS = ["Baden-Württemberg", "Hessen"]
MAP_DEFAULT_CENTER = [49.0, 9.0] MAP_DEFAULT_CENTER = [49.0, 9.0]
MAP_DEFAULT_ZOOM = 8 MAP_DEFAULT_ZOOM = 8
#: Kartenkacheln. "OpenStreetMap" braucht keinen API-Schlüssel.
#: (Die früher genutzten "CartoDB positron"-Kacheln verlangen seit 2024 einen Schlüssel.)
MAP_TILES = "OpenStreetMap"
log = logging.getLogger("arbeitsorte") log = logging.getLogger("arbeitsorte")
@@ -415,7 +419,7 @@ def generate_map(store: DataStore) -> Path:
m = folium.Map( m = folium.Map(
location=MAP_DEFAULT_CENTER, zoom_start=MAP_DEFAULT_ZOOM, location=MAP_DEFAULT_CENTER, zoom_start=MAP_DEFAULT_ZOOM,
tiles="CartoDB positron", tiles=MAP_TILES,
) )
max_count = int(freq["count"].max()) max_count = int(freq["count"].max())
+1 -1
View File
@@ -84,6 +84,6 @@ This is the file to ask for when diagnosing a problem on the user's laptop.
|------------|-----------|-------------------| |------------|-----------|-------------------|
| Nominatim (OSM) | geocoding new/edited entries | entries save with blank coords, shown as `⚠ nicht gefunden` | | Nominatim (OSM) | geocoding new/edited entries | entries save with blank coords, shown as `⚠ nicht gefunden` |
| CDN (jsdelivr, jquery, cloudflare) | rendering `karte.html` | map page loads blank / unstyled | | CDN (jsdelivr, jquery, cloudflare) | rendering `karte.html` | map page loads blank / unstyled |
| CartoDB tiles | map background | grey tiles | | OpenStreetMap tiles (`tile.openstreetmap.org`) | map background | blank/grey tiles |
Existing entries that already have coordinates do **not** need the network. Existing entries that already have coordinates do **not** need the network.
+8
View File
@@ -2,6 +2,14 @@
Notable changes to the app. Newest first. Notable changes to the app. Newest first.
## 2026-09-07 — map tiles switched to OpenStreetMap
`folium.Map(tiles="CartoDB positron")` began showing an "API KEY REQUIRED"
watermark (Carto moved its basemaps behind a key). Switched to
`tiles="OpenStreetMap"` via a new `MAP_TILES` constant — no key required. OSM
standard tiles are more colourful than positron was; `MAP_TILES` makes swapping
the provider a one-line change.
## 2026-09-07 — UI/UX pass ## 2026-09-07 — UI/UX pass
A round of usability improvements aimed at the non-technical user A round of usability improvements aimed at the non-technical user
+14
View File
@@ -36,6 +36,20 @@ Numeric parsing is deliberately deferred to `get_map_data` (`pd.to_numeric(...,
errors="coerce")`). Don't "fix" columns to float on load — blank coordinates and errors="coerce")`). Don't "fix" columns to float on load — blank coordinates and
leading-zero PLZ both depend on the string representation. leading-zero PLZ both depend on the string representation.
## CartoDB "positron" tiles now require an API key (2026-09-07)
The original `folium.Map(tiles="CartoDB positron")` started rendering an
"API KEY REQUIRED / carto.com/basemaps/apikey" watermark Carto moved its
basemaps behind a key. Switched to `tiles="OpenStreetMap"` (constant
`MAP_TILES`), which needs no key. Trade-off: OSM standard tiles are more
colourful than positron's muted grey. Other no-key options if a lighter look is
wanted: OSM Germany (`tile.openstreetmap.de`), OSM France Hot
(`{s}.tile.openstreetmap.fr/hot`) both still colourful. Truly muted
key-free basemaps are hard to find now.
Don't assume a "free" third-party tile source stays free pin the provider in
one constant so swapping it is a one-line change.
## Nominatim query order matters ## Nominatim query order matters
`geocode_city` returns the **first** hit, trying PLZ-qualified first, then each `geocode_city` returns the **first** hit, trying PLZ-qualified first, then each
+6 -5
View File
@@ -168,11 +168,12 @@ or at least skip exact duplicates by default.
## 9. Offline map 🟢 ## 9. Offline map 🟢
`karte.html` loads Leaflet/jQuery/Bootstrap from CDNs and tiles from CartoDB, so `karte.html` loads Leaflet/jQuery/Bootstrap from CDNs and tiles from
the map is blank without internet even though all the data is local. If offline `tile.openstreetmap.org` (`MAP_TILES`; switched away from CartoDB positron, which
use matters, vendor the Leaflet JS/CSS into `data/` and post-process the Folium now needs an API key). The map is blank without internet even though all the
output to point at local files (tiles would still need caching or an offline data is local. If offline use matters, vendor the Leaflet JS/CSS into `data/`
tile pack — larger effort). and post-process the Folium output to point at local files (tiles would still
need caching or an offline tile pack — larger effort).
## 10. Small code-quality items 🟢 — partly done ## 10. Small code-quality items 🟢 — partly done
+9 -4
View File
@@ -62,8 +62,9 @@ A table view of everything in `orte.csv`.
Generated by `generate_map()`: Generated by `generate_map()`:
- Base layer: `CartoDB positron`, initial view centred on `[49.0, 9.0]`, - Base layer: **OpenStreetMap** standard tiles (`MAP_TILES`) no API key.
zoom 8 (roughly Baden-Württemberg). Initial view centred on `[49.0, 9.0]`, zoom 8 (roughly Baden-Württemberg);
the view auto-fits to the markers when there is more than one.
- One **`CircleMarker`** per unique `(city, lat, lon)` group. Radius scales - One **`CircleMarker`** per unique `(city, lat, lon)` group. Radius scales
linearly with the visit count for that location linearly with the visit count for that location
(`5 + count / max_count * 20` px), colour is DRK red (`#CC0000`). (`5 + count / max_count * 20` px), colour is DRK red (`#CC0000`).
@@ -72,8 +73,12 @@ Generated by `generate_map()`:
- If there are no usable coordinates at all, a dialog says so (and the status - If there are no usable coordinates at all, a dialog says so (and the status
bar shows a warning). bar shows a warning).
> The generated HTML pulls Leaflet, jQuery and Bootstrap from CDNs, so the map > The generated HTML pulls Leaflet, jQuery and Bootstrap from CDNs, and the map
> needs an internet connection to render even though the data is local. > tiles from `tile.openstreetmap.org`, so the map needs an internet connection to
> render even though the data is local. To change the look, set `MAP_TILES` near
> the top of `app.py` to another no-key provider Folium knows
> (`"OpenStreetMap"`, `"CartoDB positron"` *now needs a key*, or a custom
> `folium.TileLayer` URL such as OSM Germany / OSM France).
## Geocoding behaviour ## Geocoding behaviour