# Where the data comes from Every figure on screen and the service it came from, including the one thing this plugin derives rather than reads. ## The one thing to understand: where the vehicles come from **opentransportdata.swiss publishes no vehicle positions.** Its GTFS-RT documentation says so outright — trip updates and service alerts only — and that feed is capped at two requests a minute anyway. There is no Swiss feed of live GPS positions to consume, from this platform or, as open data, from anywhere else. So the mark on the map is **not a reported position**. Here is exactly what it is. The planner publishes every *call* a journey makes: each stop, with a coordinate, a timetabled time, and — where the operator feeds one — a real-time estimate. Two consecutive calls bound the vehicle exactly: at the first one's departure it was there, at the second one's arrival it will be there. The position drawn is that interval, linearly divided by the clock. This is the same method every well-known Swiss live map uses, including the ones that look like they have GPS. It has three limits, and this plugin states them on screen rather than hiding them: - **The path between two stops is a straight line**, because the planner gives the stops and not the rails between them. A train rounding a curve is drawn cutting the chord. - **The speed is a segment average** — distance between two stops over the time allowed between them — not a speedometer reading. A tram stopped at a red light still reads as its segment average. Every speed on screen is labelled *derived*. - **Without real-time data the position is the timetable alone.** The vehicle card says which of the two you are looking at. What this buys is worth the honesty: interpolating between two known points is arithmetic, so the map redraws **five times a second at no network cost**, while the planner is polled every twenty seconds. The two cadences are completely separate, and that is the only way to be both smooth and lawful — see *Quota* below. The redraw *is* the animation: nothing tweens between samples. An earlier version glided between one-second samples instead, which was both slower and wrong — slower because animating fifteen markers made the whole popup recomposite at the display's refresh rate, measured at 8.8 % of a core against 1.2 % for stepping the clock; wrong because a marker easing *towards* the current position is by definition drawing where the vehicle was a sample ago. ## The map underneath The panel draws the federal topographic map faintly beneath the transport data, from [swisstopo](https://www.swisstopo.admin.ch/)'s WMTS service. swisstopo publishes it **free of charge, with no key and no registration**, for any use including commercial, on one condition: the source is credited. The panel shows *© swisstopo* whenever a tile is on screen. The choice offered is *which* map, not whether to have one. **Colour map** in the panel swaps the grey sheet for the colour one; unticked is grey, and grey is the default. There is no mapless mode: a square of stop dots with no streets under them told the user less than the same dots over a map, so it was never the better half of that choice. `basemap: false` in `shell.json` still switches swisstopo off entirely, and it is documented as a kill switch rather than offered as a mode — for the one case the panel cannot serve, somebody who needs this plugin to contact opentransportdata.swiss and nothing else. It also stops the canton lookup, which is the same provider. ### Why a second provider at all The journey planner is a *timetable* service. It answers where a vehicle is due and what it is called, and it is authoritative about that. It does not answer where anything is in the world beyond a bare coordinate per stop, and two things this plugin shows need exactly that: - **Somewhere to put the dots.** A square of stop markers with nothing under them tells you a bus passes *here* without telling you where *here* is. The national map is what turns coordinates into a place you recognise. - **The canton.** Two Swiss villages sharing a name is the ordinary case, and the canton is how everyone here tells them apart. OJP does not publish it — a stop carries a `TopographicPlaceRef` like `23024032:2` and a `TopographicPlaceName` of `Bourg-St-Pierre`, and asking for topographic places directly returns the same bare municipality. The reference does not decode to a canton either: Sion and Bourg-St-Pierre are both Valais and their references share no field. swissBOUNDARIES3D answers it directly. The two mountain presets need it a third time: the ski-touring routes and the footpath network are swisstopo sheets, and without them those ticks are mode filters with nothing to show. swisstopo is the federal mapping agency, the data is open, no key or registration is involved, and the licence asks only for credit — which the map carries. It is the same institution as the transport register, not a third-party tracker: the plugin sends it a tile index or a stop's published coordinate, and nothing about the user. ### Cache and prefetch Sheets are cached on disk and never re-fetched — the national map does not change on the timescale a panel is open — with the least recently used dropped past 400 sheets, about fifteen megabytes. A zoom step is 1.2×, and a tile level is a factor of two, so roughly every fourth notch needs six to twelve sheets that are not on disk. Fetched one at a time that was a visible pause with the map half-built. Two things fix it: - **The last complete set stays drawn underneath** while the new one fills in. Tiles are positioned by their own geographic bounds, so a coarser sheet lands in exactly the right place at the new scale. The map sharpens instead of blanking, and it costs no requests at all. - **The level either side is fetched in advance**, on a second queue that is only drained when nothing on screen is waiting. Zooming out keeps the whole extent so the level below is prefetched over all of it — coarser means fewer sheets, so it is nearly free. Zooming in keeps the middle and throws the rim away, so the level above is prefetched over the middle only: thirty sheets became nine, and the two thirds dropped covered ground that stops being on screen the moment you use it. Favourites are prefetched too, at the extent the map is currently showing. A saved place is one the user has said they will come back to, which makes it the least speculative prefetch there is — but only at that one extent, because guessing their zoom as well would multiply the requests for a guess that is no longer well founded. Measured at Bern, opening on a 1 km view: 43 sheets, being the nine on screen, twenty-one for three favourites, four for the level below and nine for the middle of the level above. A zoom crossing a level afterwards is complete within a frame or two. A jump of several levels at once still has ground nobody has ever fetched, and shows the last complete set in the middle while the rest arrives. The map is drawn deliberately faint. The national map is a dense product, and at full strength under a 1 km view it wins every contrast fight against a twelve-pixel vehicle. Drawn faintly it stops competing and starts helping. The distance grid is suppressed underneath it — the streets are already answering that question. The colour sheet is drawn fainter than the grey one by default. Measured on a themed panel the two reach the same *luminance* at the same opacity, but colour also brings saturated greens, yellows and reds, and those compete with a marker drawn in the theme's single accent hue in a way grey ink never does. Tiles are cached under `~/.cache/omarchy/plugins/jmaeder.swisstransport/tiles` and only fetched when the map moves, because swisstopo's terms reserve the right to restrict access under heavy use. Nothing there expires on its own — the national map does not change on the timescale a panel is open — so the cache is capped at 400 sheets, about fifteen megabytes, and the least recently fetched are dropped past that. Only files matching the plugin's own naming are ever deleted; anything else in that directory is left alone. One line under the ticks says what the map is and where it comes from, shown whenever there is one — the plugin is contacting a second host, and that is something to say on screen rather than only in a README. ## Quota The Open Journey Planner's free tier is 50 requests a minute and 20 000 a day. Those are limits on *your key*, so exceeding them throttles you, not the plugin. The defaults sit well inside them — six stops every twenty seconds is eighteen requests a minute — but the timers are a hope, not a guarantee, so there is also a check. A token bucket held deliberately below the published figures (40 a minute, 15 000 a day) is consulted before every single request, and a refused request is **dropped rather than queued**, because a queued burst is how a rate limiter gets hit twice. Requests go out one at a time through a single process rather than fanning out, for the same reason. ## Sources and licence Transport data from [opentransportdata.swiss](https://opentransportdata.swiss/) (Open Journey Planner 2.0). National map © [swisstopo](https://www.swisstopo.admin.ch/), which also supplies the ski-touring and footpath sheets and, through swissBOUNDARIES3D, the canton a place is in. Coarse first-run geolocation by [ipapi.co](https://ipapi.co/). This plugin is MIT licensed — see [LICENSE](LICENSE). The data it displays is governed by the terms of the services above.