Brandýs-Boleslav
Začni psát pro vyhledávání...

Code review: „Předělej mapu parkování podle oblastí” (63105d3)

Code review: „Předělej mapu parkování podle oblastí” (63105d3)

Větev codex/parkovani-oblasti, 11 souborů, +1538 −142. PR na GitHubu zatím neexistuje, review je proti commitu.

Kolo 1 — 2026-08-02 17:35. Stav: dvě blokační připomínky, čtyři doporučené, čtyři drobnosti. Celkově je změna dobře postavená: párování přes kód ZSJ místo pořadí řádků je správná reakce na doloženou chybu v podkladech, generátor je reprodukovatelný a testy dávají smysl. Blokační výhrady míří na to, co uvidí čtenář na mapě, ne na architekturu.

Kolo 2 — 2026-08-02 18:20, commit 2f2a3a5. Obě blokační připomínky vypořádány, review uzavřeno. Vypořádány jsou i všechny čtyři doporučené a všechny čtyři drobnosti; podrobnosti a způsob ověření jsou v sekci Kolo 2 na konci. Přibyly tři nové drobnosti (M5–M7), žádná není blokační.

Blokační

B1 — Šedé ulice nemá legenda

js/parkovani.js, vyrazBarevUlic(): úsek bez obsazenosti se kreslí #9aa4ab. Takových je 198 z 927 úseků (21 %), tedy 91 z 239 ulic — jde o ulice s nulovou legální kapacitou. Oblastní vrstva má pro týž jev vlastní barvu i řádek legendy („vozidla, ale 0 legálních stání”), uliční vrstva nic. Čtenář šedou přečte jako „bez problému” nebo „bez dat”, přitom znamená pravý opak: auta tam stojí, legální stání tam nejsou žádná.

Náprava: přidat do legendy řádek pro uliční šedou (stačí zobrazovat jen tehdy, když je uliční vrstva viditelná, tj. nad zoom 14,5 a mimo metriku Obyvatele).

B2 — Počty vozidel v oblastech nejsou z repa doložitelné

data/parkovani-oblasti.json obsahuje 20 ručně přepsaných řádků tabulky 3.1. Ta v repu není v žádné strojově čitelné podobě a tools/test_parkovani.mjs kontroluje součty proti konstantám zapsaným v testu — kruhová kontrola, která přepis nezachytí.

Kapacity sedí na jiný zdroj přesně (agregace data/parkovani.json po ZSJ dává 5164 legálních a 7426 technických míst, tedy 1:1). Počty vozidel ale u dvou ZSJ výrazně nesedí na agregaci surových dat z data celoplošné brandýs public.xlsx:

ZSJ v commitu (noc) agregace xlsx po ZSJ rozdíl
Zahradní město 158 34,5 4,6×
U nádraží 1285 1152,5 +11 %

U Zahradního města jde rozdíl přesně na vrub dvou dělených řádků tabulkové přílohy (729-1, 729-2, Rozmarýnova: noc 86 + 37 = 123). To jsou řádky z té části podkladu, o níž docs/parkovani-kontrola-codex.md v tomtéž repu dokládá, že hodnoty OA patří jinému úseku (poziční spojení dvou různě seřazených seznamů). Dopad na výstup je viditelný: 158/159 míst je 99 % obsazenost (žlutá třída), 34,5/159 je 22 % (nejsvětlejší zelená) — čtyři třídy legendy rozdíl.

Nejde nutně o chybu, tabulka 3.1 může mít vlastní, správnější podklad. Ale .impeccable.md, přidaný stejným commitem, si v bodě 5 sám ukládá, že „čísla musí být reprodukovatelná ze zdrojových dat”, a tady to neplatí.

Náprava (stačí jedna z variant):

  • přiložit tabulku 3.1 jako CSV/JSON do repa a testovat vstup proti ní;
  • nebo u obou dotčených oblastí přiznat nejistotu v detailu oblasti a poznámku zapsat i do data/parkovani-oblasti.json.

Doporučené

D1 — Test neváže výstup na aktuální vstup

test_parkovani.mjs porovnává geojson s konstantami, ne se vstupním JSON. Úprava nazev, populacniZsj nebo vzájemně se rušících hodnot bez regenerace projde zeleně. Doporučuji porovnat per-ZSJ mistaLegalni, mistaTechnicka, vozidlaNoc/Den mezi parkovani-oblasti.json a parkovani-oblasti.geojson.

D2 — Uliční vrstva ukazuje hodnoty jiné oblasti, než v níž leží

Uliční data jsou agregovaná na celou ulici, oblastní na ZSJ. Geometrickým testem (střed úseku v polygonu ZSJ) leží ve „své” ZSJ jen část úseků: Před obchvatem 97 %, Vrábí 99 %, ale Na Zápské 41 %, Průmyslový obvod 20 %, U Záp a U Proboštského rybníka 0 %. Na mapě tak nad zelenou oblastí leží červené ulice a naopak. Popup to zmiňuje poslední větou; zvážil bych to říct dřív a výrazněji, nebo uliční detail omezit na vybranou oblast.

D3 — Choropleth přeceňuje neobydlené plochy

U Proboštského rybníka (18 obyvatel, 17 vozidel, 0 legálních stání) je fialově přes celou oboru a při běžném zoomu vizuálně dominuje mapě víc než Spořilov, kde chybí 294 stání. Zvážit ztlumení výplně u oblastí s malou populací nebo šrafu místo plné barvy.

D4 — Kontrast a velikost písma v panelu

.pk-graf-metodika#98a2a8 na bílé = 2,6:1 při 10,5 px, tedy pod WCAG AA (4,5:1). Popisky v panelu jdou až na 9,5 px (.pk-detail-kicker, .pk-stitek); u webu pro veřejnost bych nešel pod 12 px.

Drobnosti

  • M1 tools/parkovani-oblasti.py, nacti_populaci(): tvrdá kontrola součtu 19029 shodí generátor i po legitimní aktualizaci RÚIAN. Doplnit do hlášky, co má člověk udělat.
  • M2 Selže-li pridejParkovani() až po addSource, další zapnutí režimu skončí na „source already exists”. Uklidit zdroj v catch.
  • M3 vyrazBarev() používá ['to-number', ['get', pole]]; null se změní na 0, tedy na nejpříznivější třídu. Dnes taková oblast v datech není (case ošetří bez_pruzkumu i nulova_kapacita), ale pojistka chybí.
  • M4 .impeccable.md je konfigurace nástroje v kořeni veřejného repa; spíš patří do docs/ nebo do .gitignore.

Co jsem ověřil

  • node doprava/tools/test_parkovani.mjs — prochází.
  • python3 doprava/tools/parkovani-oblasti.py — regenerace je bit-identická s commitnutým geojsonem (prázdný git diff).
  • Všech 24 kódů ZSJ odpovídá číselníku ČSÚ (dotaz na RSO_2021_2 podle KOD_OBEC='538094'), včetně netriviálních mapování K Toušeni → Královice, Před obchvatem → Před dálnicí, U kostela → Stará Boleslav-historické jádro.
  • Názvy v populacniZsj sedí na mhd-brandys/addr_pop.csv (24 ZSJ, 19 029 obyvatel).
  • Kapacity: agregace tabulkové přílohy po ZSJ dává přesně hodnoty v commitu u všech 20 oblastí.
  • V prohlížeči (lokální build): načtení bez chyb konzole, přepínání všech tří metrik, výběr z žebříčku i bodového grafu, přiblížení na uliční vrstvu, přepínání režimů Živě / Simulace / Parkování tam a zpět — bez výjimek. Souhrn 103,4 %, Spořilov 214,4 % a +294 vozidel sedí na data.
  • Ošetření souběhu v app.js (sdílený promise + kontrola stav.rezim po await) je správné, dvojímu addSource brání.

Kolo 2 — vypořádání v 2f2a3a5

Commit „Vypořádej připomínky k mapě parkování”, 9 souborů, +176 −38.

Blokační — obě vyřešeny

B1 (šedé ulice) — vyřešeno. Přibyla vrstva parkovani-ulice-nulova (fialová čárkovaná, filtr kapacitaZakonna == 0), parkovani-ulice-linie dostala doplňkový filtr > 0 a legenda dostala sekci „Uliční detail při tomto přiblížení”, která se objeví jen nad zoomem 14,5 a překresluje se na zoomend.

Ověřeno: všech 198 dříve šedých úseků má kapacitaZakonna == 0, novou vrstvu tedy pokrývá filtr beze zbytku a šedá už na uliční vrstvě nevznikne (úseků s kapacitou > 0 a chybějící obsazeností je 0). Oba filtry jsem vyhodnotil proti @maplibre/maplibre-gl-style-spec — doplňují se bez překryvu i mezery.

B2 (nedoložitelné počty vozidel) — vyřešeno zvolením druhé nabídnuté varianty: U nádraží a Zahradní město mají v datech spolehlivostVozidel: "nejista" a poznamkaDat s konkrétním číselným rozdílem i odkazem na dělené řádky 729-1/729-2, v detailu oblasti se zobrazí štítek „nejistá data” a žlutý blok s vysvětlením. Test kontroluje, že příznak nese právě tato dvě ZSJ a že poznámka není prázdná.

Doporučené — všechny čtyři vyřešeny

  • D1 — test nově porovnává per-ZSJ nazev, populacniZsj, kapacity i vozidla mezi vstupním JSON a výstupním geojsonem. Ověřeno experimentem: změna názvu Vrábí bez regenerace shodí test hláškou Výstup neodpovídá vstupu: 009105.nazev (data i test jsem vrátil zpět).
  • D2 — popup uličního detailu má upozornění hned pod názvem: „Souhrn platí pro celou ulici a nemusí odpovídat barvě oblasti pod ní.”
  • D3 — oblasti pod 100 obyvatel mají fill-opacity 0,38 a čárkovaný obrys. Ověřeno vyhodnocením výrazu: U Proboštského rybníka (18 obyvatel) → 0,38, Spořilov (1 805) → 0,66.
  • D4.pk-graf-metodika je nyní #596974/11,5 px, tj. 5,68:1 místo 2,6:1. Přeměřil jsem i ostatní nové kombinace: 5,5–7,8:1, všechny nad AA. Nejmenší text v panelu stoupl z 9,5 px na 10,5–11,5 px; pod 12 px zůstaly jen popisky os SVG grafu (9–9,5 px), tam je kontrast 5,7:1.

Drobnosti — všechny čtyři vyřešeny

  • M1 — konstanta OCEKAVANY_POCET_OBYVATEL a hláška říká, co udělat.
  • M2uklidParkovaciVrstvy() v catch odstraní vrstvy i zdroje, interakceNastavena brání dvojí registraci posluchačů.
  • M3vyrazBarevOblasti() má case pro null. Ověřeno vyhodnocením: změřená oblast s obsazenostNoc == null#9aa4ab, ne nejsvětlejší třídu.
  • M4.impeccable.md přesunut do doprava/docs/design-context.md.

Nové drobnosti z tohoto kola

  • M5 — podmínka pro legendu uličního detailu testuje jen viditelnost, metriku a zoom, ne existenci vrstvy. Když se parkovani-mapa.geojson nenačte (nactiGeojson(…, false) vrátí null, vrstvy nevzniknou), legenda bude popisovat neexistující ulice — a to zároveň se stavovou hláškou, že se uliční detail nepodařilo načíst. Přidat mapaInstance?.getLayer('parkovani-ulice-linie').
  • M6 — štítek „nejistá data” v detailu nahrazuje štítek „priorita” (ternární operátor). Dnes se ta dvě označení nepřekrývají, kdyby ale ano, priorita zmizí beze stopy.
  • M7 — legenda uličního detailu nabízí řádek „obsazenost nelze spočítat” pro šedou, která po B1 v datech nevzniká ani jednou. Neškodné, ale zbytečné.

Ověřeno

node doprava/tools/test_parkovani.mjs prochází, regenerace generátorem je bit-identická s commitnutým geojsonem, výrazy a filtry MapLibre jsou validní podle style-spec a vyhodnocují se podle očekávání.

Vizuální kontrolu v prohlížeči jsem tentokrát nedokončil: aplikace uvízne na čekání na mapa.isStyleLoaded(), protože se v prohlížeči nestahuje mapový styl z CARTO CDN (žádné požadavky na dlaždice, WebGL v pořádku). Chová se tak stejně na cf447a8 i na 2f2a3a5, nejde tedy o regresi tohoto commitu, ale o stav prostředí. Legendu uličního detailu a štítek nejistoty jsem proto ověřil jen z kódu a z vyhodnocení výrazů, ne na živé mapě.