English · Magyar

Fejlesztési napló

Az egész brit vasúthálózat egy térképen – a rég bezárt állomásokkal együtt

Vanilla JavaScriptes térkép Nagy-Britannia minden vasútvonaláról és állomásáról, elejétől a végéig nyílt adatokból. Elmesélem, hogyan állt össze, milyen adatbukfencek voltak mögötte, és mi vitte előre az egészet.

Szerző: optional.org.uk · 2026. május 31. · trainmap.co.uk ☕ Hívj meg egy kávéra

Vanilla JavaScriptes térkép Nagy-Britannia minden vasútvonaláról és állomásáról, elejétől a végéig nyílt adatokból. Elmesélem, hogyan állt össze, milyen adatbukfencek voltak mögötte, és mi vitte előre az egészet.

Egyetlen térképet szerettem volna, amin ott van a teljes brit vasúthálózat. Nem annyi, amennyit egy útvonaltervező megmutat, hanem minden: a nosztalgiavasutak, a csak tehervonatok járta összekötő vágányok, a névvel bíró alagutak és viaduktok, és az a több ezer állomás is, amelyik valamikor létezett, ma viszont már nem. (Nagyjából az az érzés, mint amikor itthon próbálod kideríteni, merre futott egy réges-rég felszedett mellékvonal – csak brit léptékben.) Ilyen térképet nem találtam, úgyhogy megcsináltam: trainmap.co.uk. Nincs hozzá app, nincs regisztráció, nincs fiók. Gyorsan betölt, és kereshetsz benne irányítószámra, állomásnévre, hárombetűs állomáskódra vagy vonalnévre.

Egy ilyen projektben a kód a kisebbik fele. Az izgalmas rész az, hogy mi minden derül ki az adatokból, ha egyszer láthatóvá teszed őket, kik használják a végén, és hányféleképpen tud a valós vasúti adat csendben ellentmondani önmagának. Ami viszont tényleg jóvá tette a térképet, az a használókkal kialakult visszajelzési kör volt: korán megmutattam, és hagytam, hogy azok mondják meg, mi a hibás, akik a legjobban ismerik a vasutat. Erről a végén részletesen is írok.

Ki mit tett hozzá

Színkóddal jelöltem meg a cikket, hogy látszódjon a valóság: melyik döntés mögött álltam én, melyik mögött az AI-ágens segítsége, és melyik mögött a közösség.

A jelölés végig ugyanaz:

Az adatprobléma

Minden vonal és állomás az OpenStreetMapről származik, az Overpass API-n keresztül lekérve. Az OSM brit vasúti lefedettsége kiváló – sokkal jobb, mint azt bárki gondolná –, mert olyan emberek gondozzák, akiknek tényleg fontos egy-egy iparvágány sorsa.

Csakhogy már az is csapda, hogy a lekérdezést „az Egyesült Királyságra” szűkítsd. Egy Nagy-Britannia köré húzott téglalapba beleesik Dublin, a Man-sziget és Észak-Franciaország aggasztóan nagy része is. Kiszúrtam ezeket az odatévedt külföldi vonalakat; a megoldás pedig az lett, hogy az ágens közvetlenül a GB közigazgatási határt (ISO3166-1=GB) kérte le az Overpasstől, és arra vágott. Így benne marad Észak-Írország – hiszen egyesült királyságbeli térképről van szó –, de kimarad az Ír Köztársaság, a Man-sziget és Calais, méghozzá kézzel belőtt szélességi fokok nélkül, amik amúgy is elromlanának abban a pillanatban, ahogy valaki felvisz egy új vonalat a határ közelében.

A vonalakat csempénként szedem le az Overpassról: egy durva, nagyjából harminccellás rács fedi Nagy-Britanniát, és minden cella csak a GB-határon belüli vasúti way-eket (vonalelemeket) kéri, mert egyetlen országos lekérdezés egész egyszerűen időtúllépéssel elhalna. A letöltés folytatható: a már lementett, érvényes cellákat átugorja, így egy félúton megszakadt futás csak a hiányzó darabokat pótolja. Utána egy feldolgozó lépés OSM-azonosító alapján kidobja a duplikált way-eket (a cellák a széleiken átfednek), a railway címke alapján három csoportba sorolja őket (nagyvasút, könnyűvasút, felhagyott vonal), minden koordinátát öt tizedesjegyre kerekít – ez nagyjából egy méter, vagyis komoly méretcsökkenés látható veszteség nélkül –, végül kiírja azt a GeoJSON-t, amit a térkép betölt, plusz egy kis „vonalnév → befoglaló keret” indexet, hogy vonalnévre is lehessen keresni. Az egészet néhány száz sor Python intézi.

Az állomások, amelyek füllentettek

A NaPTAN-nal kezdtem, ez a brit tömegközlekedési megállók hivatalos adatbázisa. A nagyvasúthoz remek, egy furcsasága viszont van: rengeteg nosztalgiavasúti állomást villamos vagy metró kategóriába sorol. Amikor tehát „vasútállomásokra” szűrtem, egész nosztalgiavonalak ürültek ki félig – pontosan erre célzott az a fórumtag is, aki szóvá tette, hogy a Swanage Railwaynek mindössze egyetlen állomása maradt a térképen.

Az állomások így átkerültek az OSM-re, ami viszont új gondot hozott: az OSM állomáscímkézése következetlen, vagyis nekem kellett eldöntenem, mi számít nagyvasúti, illetve nosztalgiaállomásnak. A szabályokat aztán az ágens dolgozta ki:

És persze a kézenfekvő szűrő, a hárombetűs ref:crs kód pont itt volt használhatatlan: a londoni metró állomásai ugyanabban a mezőben viselik a TfL „Z” kezdetű kódjait.

Nosztalgiavasutak és a Swanage-ügy

A megőrzött, nosztalgiavonalak külön színt kapnak a térképen. Az OSM-ben a railway:preserved vagy a usage=tourism címke jelöli őket – megint csak nem következetesen. A Swanage Railway üzemelő vágánya például helyenként egyszerű szárnyvonalként szerepel, így először sima National Rail vonalként jelent meg, egészen addig, míg valaki a fórumon finoman meg nem jegyezte, hogy a swanage-i szárnyvonalat nosztalgiából National Raillé léptettem elő.

A javítás egy kis heurisztika lett, ami úgy gondolkodik, ahogy egy ember olvassa a térképet: a nosztalgiajelölés terjedjen ki minden olyan szakaszra, amelyik ugyanazt a vonalnevet viseli. Ha a „Swanage Railway” bármelyik darabja megőrzöttként van felvéve, az egész névvel bíró vonal lila lesz. Durva megoldás, de sokkal többször talál, mint ha szakaszonként bíznánk a címkékben.

Ez a visszatérő motívum: a nyílt adat ritkán hibás, viszont gyakran következetlen. A munka java része apró, jól olvasható szabályok írása, amelyek úgy oldják fel az ellentmondást, ahogy egy ember tenné.

Vonalak, amelyek kicsinyítéskor kiegyenesedtek

Apró hiba, de jó példa a felhasználókkal folytatott oda-vissza beszélgetésre. Egy fórumtag jelezte, hogy a Northallerton környéki pálya „töröttnek” látszik: a finom ívek bizonyos nagyítási szinteken egyenes húrokká váltak. A saját gépét már ki is zárta a gyanúsítottak közül, hat böngészőben végigpróbálva. A leírása – az északi végén ránagyítva helyreáll, kicsinyítve újra eltörik, a déli csomópont pedig egyáltalán nem áll helyre – elég volt a behatároláshoz.

Az ok az, hogy a MapLibre alapból nagyítási szintenként egyszerűsíti a GeoJSON-geometriát (Douglas–Peucker-módszerrel), hogy a nagy vektorrétegek olcsók maradjanak. A legtöbb adatnál ez teljesen ésszerű. Egy vasúti térképnél viszont épp fordítva áll a dolog: a pálya pontos alakja maga a lényeg. Az egész javítás egyetlen tulajdonság a forráson: tolerance: 0. Az ívek azóta minden nagításon hűek maradnak. A hibát jelző felhasználó vissza is igazolta, hogy ezzel az ő esete és egy másik, Low Fell közelében észrevett hiba is megoldódott. A javítás egy sor volt – a megtalálásához vezető beszélgetés viszont ennél sokkal többet ért.

Egy hiba helyén nő a következő

Ez a tolerance: 0 szép példa arra, hogyan készíti elő az egyik javítás csendben a másikat. Az egyszerűsítés kikapcsolása minden csúcspontot megtart minden nagításon – pontosság szempontjából pont ezt akarod, memória szempontjából pont ezt nem. Az egész hálózat nagyjából 28 MB GeoJSON, durván 720 000 csúcsponttal, és mindez egyszerre volt a memóriában. Laptopon rendben is van. Egy középkategóriás telefonon viszont a böngészőfül egyszerűen összeomlott, főleg ha bekapcsoltál mellé még egy nehéz réteget.

Az őszinte megoldás nem az, hogy eldobjuk a részleteket, hanem hogy ne töltsük le azt, amit úgysem látsz. A geometriában gazdag nagyvasúti hálózatot átállítottam vektoros csempés megjelenítésre (PMTiles formátumra): így a geometria már build időben, nagyítási szintenként csempékre van vágva, a böngésző pedig HTTP range-kérésekkel csak az éppen képernyőn lévő néhány csempét szedi le. A memóriaigény innentől a látómezőt követi, nem az egész országot. Egyetlen statikus fájl, ugyanazon a tárhelyen, csempeszerver nélkül – a csempézést végző tippecanoe pedig rendesen, nagyítási szintenként végzi az egyszerűsítést, úgyhogy a vonalak mindenhol hűek maradnak, és a húrra ugró hiba sem tér vissza.

A GeoJSON megmaradt tartalékként, de innentől a csempék az alapértelmezettek. Ez az a fajta változtatás, amit észre sem veszel – egészen addig, míg egyszer csak össze nem omlik a kezed alatt.

Állomások, amelyek már nincsenek

Ez a kedvenc részem. Egy barátom szólt, hogy a wiltshire-i Box állomás hiányzik. Igaza volt: Box 1965-ben bezárt, és egész egyszerűen nincs benne az OpenStreetMapben – sem működőként, sem felhagyottként.

Honnan szerzel akkor évtizedekkel ezelőtt megszűnt állomásokat? A Wikidatából (CC0). A bökkenő az, hogy a bezárási adatai hiányosak. Box Wikidata-tételében egyáltalán nincs bezárási dátum – a mező üresen áll, ahogy sok más megszűnt állomásnál is –, miközben a Wikipédia-szócikke készségesen elárulja, hogy 1965. január 4-én zárt be. (A Wikidata azért megjelöli egy homályos „decommissioned”, vagyis üzemen kívül helyezett státusszal, csak épp dátum nélkül.) Vagyis ha a „van bezárási dátuma” szűrőre hagyatkoznánk, pont azokat az állomásokat hagynánk ki, amiket keresünk.

A bevált megközelítés végül a kivonás lett. Lekérdeztem az összes egyesült királyságbeli vasútállomást, amiről a Wikidata tud – nagyjából 9600-at –, majd kivettem belőle azokat, amelyek még léteznek, vagyis egy mai OpenStreetMap-állomás 250 méteres körzetébe esnek. Ami marad, valamivel több mint 6100 állomás, épp az a halmaz, ami valaha létezett, ma viszont már nem. Box is köztük van. Ez most külön bekapcsolható réteg, üres körökkel rajzolva; bármelyikre kattintva eljutsz a Wikipédia-szócikkéhez.

(Lábjegyzet az érdeklődőknek: a Wikidata-lekérdezéseket a QLever tükrén futtattam, mert a hivatalos végpont túl szigorúan van sebességkorlátozva.)

Az összefűzés a nehéz

Kicsit hátrébb lépve: a feldolgozási lánc valójában néhány adathalmaz összefűzése, a bökkenő pedig az, hogy egyiknek sincs közös azonosítója a másikkal. Az OpenStreetMap adja a geometriát és a működő állomásokat, de következetlenül címkéz, és a bezárt állomásokról semmit sem tud. A bezártak a Wikidatából jönnek, gyakran – ahogy láttuk – bezárási dátum nélkül. Az irányítószámos kereséshez a postcodes.io szolgáltat adatot (a háttérben ONS-adatokból). A NaPTAN, a hivatalos megállónyilvántartás volt az állomások kiindulópontja, egészen addig, míg ki nem derült, hogy túl sok nosztalgiaállomást sorol villamos és metró alá. Mindegyik forrás valamiben mérvadó, másban pedig használhatatlan.

Mivel nincs közös kulcs az összefűzéshez, a szkriptben szinte minden érdemi döntés földrajz vagy név alapján születik:

Ezek közül néhány – valljuk be – inkább következtetés, mint tény: a nosztalgiaszín és a „korábbi állomás” címke származtatott, egyik forrás sem mondja ki közvetlenül. Kitalálva semmi nincs, minden pozíció és név visszavezethető az OpenStreetMapre, a Wikidatára vagy az ONS-re, de ezek heurisztikák – egy heurisztika pedig pontosan annyit ér, amennyit teszteled.

Valójában ezért számított annyit a fórum. A szabályokat meg tudtam írni, de nem volt megbízható módszerem eldönteni, hogy jók-e: hogy a Swanage-terjesztés minden szakaszt elkap-e, hogy a keskeny nyomtávú teszt nem túl szigorú-e, hogy egy ardwicki „covered” címke valóban alagútnak számít-e. Az ottaniak viszont tudták. Minden hibajelzés gyakorlatilag egy bukott teszteset volt a feldolgozási láncra, olyanoktól, akik nálam sokkal jobban ismerték a terepet. Az adatok csak azért állnak jól össze, mert a rajongók elé tettem őket, ők pedig megmondták, mi a hibás és min lehetne javítani.

Apróságok, amiktől kész lett

Hogy meg is mozduljon

A térkép hónapokig állókép volt az infrastruktúráról. A kézenfekvő kérdést szinte mindenki feltette, akinek megmutattam: jó, jó, de hol vannak a vonatok most? A válasz a Darwin, a National Rail valós idejű vonatinformációs rendszere – ugyanaz, ami az állomási indulási táblákat hajtja. Bárki hozzáférhet a Rail Data Marketplace-en keresztül, egy rövid regisztráció és jóváhagyás után. Én arra a régi vágású adatfolyamra készültem, amiről mindenhol írnak – egy 2005-ös protokollt beszélő üzenetsorra, gzippelt XML-lel –, ehelyett modern Kafka-streamet kaptam, JSON-nal, ami este tizenegykor percenként nagyjából 1300 üzenetet szállított. A fogyasztó, a vonatonkénti állapotkövetés és az a motor, ami az „ekkor haladt át ezen a menetrendi ponton” jelentésekből a megfelelő vágányszakaszon mozgó pöttyöt csinál, még aznap este megépült és futott.

Aztán jött az ismerős probléma: újabb adathalmaz, újabb azonosítóval, amit rajta kívül senki nem használ. A Darwin TIPLOC-kal (timing point location) nevezi meg a helyeket, a térképen viszont semmi nem beszél TIPLOC-ul. A megoldás váratlan irányból érkezett: a NaPTAN – az a megállónyilvántartás, amit az állomások miatt korábban lecseréltem, mert kisvasutakat tartott nyilván villamosként – minden vasúti megálló azonosítójába belekódolja a TIPLOC-ot: a kód szó szerint a 9100 előtag, utána a TIPLOC. Az adathalmaz, ami a nosztalgiavasutakról füllentett, keresőtáblaként törlesztette az adósságát: 2700 menetrendi pont került a helyére.

Maguk a pozíciók származtatottak, nem mértek. A vonatok nem sugároznak GPS-t; a Darwin azt jelenti, hogy egy vonat mikor érkezett meg, mikor indult el, vagy mikorra várható az egyes megállási pontokon. Az a gráf, amit korábban egy „ki lehet-e számolni az útvonalat két állomás között?” kísérlethez építettem, hirtelen maga lett a termelési motor: minden vonatot a legutóbbi és a következő megállási pontja közé teszünk, az eltelt idő arányában, a valódi vágányon. Egy kis munkafolyamat egy meglévő szerveren fogyasztja a streamet, és tizenöt másodpercenként kiír egyetlen statikus fájlt. Az oldal marad az, ami mindig is volt – fájlok egy polcon –, a térkép pedig egyszerűen azt az egy fájlt kérdezgeti, amelyik változik.

Legalább ennyit számított, hogy jól is nézzen ki. Egy pötty, ami tizenöt másodpercenként odébb teleportál, hibásnak hat, ezért minden vonat magával hozza a saját útvonalának következő kilométerét is, a böngésző pedig e mentén csúsztatja a frissítések között: a vonatok követik a kanyarokat, és a haladási irányukba néznek. Ahol az adatfolyam jelenti a szerelvény összeállítását, ott a kocsik pöttysorként húzódnak a nyíl mögött – egy nyolckocsis expressz láthatóan kígyózik a kanyarban, míg egy kétkocsis személyvonat kurta marad. Ahol viszont semmilyen adat nem mondja meg, milyen hosszú a vonat, ott a térkép nem rajzol kocsikat: a tehervonatok hossza nem nyilvános, úgyhogy a tehervonat nem kap kitalált kocsikat. A „semmit nem találunk ki” szabály a szépség kedvéért sem hajlik meg.

Aztán kitettem egy vasutas subredditre, és az a kör, ami a térkép többi részét felépítette, kétszeres sebességgel indult újra. Egy napon belül kiderült, hogy a felugró panelen látható kód a Darwin belső menetrend-azonosítója, nem vonatszám („mi az az L78543?”); hogy a „következő megálló” néha olyan állomás, amin a vonat 145-tel átrobog; hogy egy útközben lévő vonat csak az útvonala addig látott szakaszát mutatja; hogy a vonatok láthatatlanul ülnek a kiindulási állomásukon; és hogy egy Moorgate felé tartó vonat a bejelentés szerint „felfelé tolatott a Canonbury-íven, pedig a közelében sem járt”. Mindegyik órákon belül javítva lett, a mély javítás pedig szerkezeti volt: bekötöttem a napi menetrendfájlokat, hogy minden vonat már az első feltűnésekor tudja a valódi vonatszámát, üzemeltetőjét és teljes útvonalát. Ugyanennek köszönhető a felugróban a Wikipédiára mutató „Class 802” járműtípus is.

A Darwin a személyszállítás – én viszont a teherforgalmat is akartam. Az a Network Rail saját nyílt adatfolyamaiban él: a TRUST nevű rendszer mozgásjelentéseiben és az országos menetrendben, ami minden tehervonati menetet tartalmaz. Egy második fogyasztó ezeket a jelentéseket illeszti a napi tehervonati menetrendekhez, és ugyanarra a térképre teszi a konténervonatokat, a kőszállítókat és a gépmeneteket – tompább, sötét szegélyű rajzolattal, pipálható kapcsolókkal: személy, teher vagy mindkettő.

A legvasutasabb fejlesztés maradt utoljára. A hozzászólók folyton a train describer adatfolyamot emlegették – a biztosítóberendezés saját nyilvántartását arról, ahogy a vonatok szakaszról szakaszra lépnek –, joggal figyelmeztetve, hogy a több tízezer szakasz valódi helyekhez kötése „óriási meló”. Már többnyire nem az: a Network Rail közzéteszi azt a referenciaadatot, ami a szakaszlépéseket menetrendi pontokhoz köti, és egy délelőttnyi csővezeték-építés az élő biztosítóberendezési események harmadát kemény pozíciófixszé alakította. Ahol ez a lefedettség megvan, ott a vonatok nem oda kerülnek, ahol a menetrend szerint lenniük kellene, hanem oda, ahol a jelzők utoljára látták őket – a felugró pedig mért sebességet mutat („~200 km/h”), egy kis „i” gombbal, ami pontosan elmagyarázza, honnan jön a szám. Egy megkérdőjelezhetetlen adat ugyanis olyan adat, amiben nem szabad megbízni.

A térkép továbbra is őszintén megmondja, hol becsül – de nézni, ahogy egy késésben lévő, borostyánsárga vonat kifűzi magát egy pályaudvarról a zöldek között, olyan sebességgel, amiért a jelzők kezeskednek, olyan vágányon, amiről tudod, hogy valódi… Ettől érződik elevenebbnek, mint valaha.

Amitől tényleg jó lett

A térképet korán és nyersen tettem ki egy brit vasútrajongó fórumra, mindenféle hátsó szándék nélkül, csak hogy lássam, tetszik-e bárkinek. Aztán a következő pár napot azzal töltöttem, hogy javításokat adtam ki, amíg a téma élt. Nem volt terv és nem volt ütemterv; az ütemterv az volt, amit utoljára észrevett valaki, és a legtöbb változás órákon belül élesbe került.

Ebben semmi újdonság nincs. Ez a szoftverfejlesztés legrégebbi gondolata, ugyanaz, amit az Agilis kiáltvány is lefektetett, még mielőtt az „agilis” értekezletekkel teli naptárt kezdett volna jelenteni: rövid, őszinte visszajelzési kör a dolgot használó emberek és aközött, aki változtatni tud rajta – és hajlandóság arra, hogy a visszajelzésre most reagálj, ne majd. A folyamatok ezt könnyen elnyelik. Egy fórumtéma, tele olyanokkal, akiknek tényleg fontos a téma, egyszerűen visszaadta nekem. Ez az a része a projektnek, amit a leginkább ajánlanék másolásra, bármit is építs éppen.


Nyisd meg a térképet →

A trainmap.co.uk ingyenes és reklámmentes.
Ha hasznosnak találod, fontold meg:

☕ Hívj meg egy kávéra