poniedziałek, 30 grudnia 2019

Sylwester w Lututowie

Początek roku to termin wprowadzania zmian na mapie administracyjnej Polski, to znaczy przesuwania granic, zmiany statusu, podziałów i fuzji.

W tym roku na szczęście żadna gmina nie podzieli losu zlikwidowanych przed rokiem Ostrowic, natomiast cztery miejscowości (Lututów, Czerwińsk nad Wisłą, Piątek i Klimontów) odzyskają prawa miejskie, utracone jeszcze w czasach carskich.

To świetna okazja, żeby przyjrzeć się możliwościom, jakie oferuje pakiet języka Python (w wersji 3) o nazwie Matplotlib-Basemap i szybko narysować mapę z nowymi miastami.



Do narysowania powyższej mapki wystarczy ok. 25 linijek kodu w Pythonie.



Instalacja

Instalacja matplotlib-basemap pod Linuksem jest banalna i np. w Ubuntu sprowadza się do zainstalowania paczki dostępnej w repozytoriach systemowych (plus drugiej – dość sporej – z danymi na temat linii brzegowej, rzek, jezior itp.).

Kartografowie z Windows nie mają tak łatwego życia – wersja dostępna przez instalator pip jest dość wiekowa, albo nie zawsze da się zainstalować; osobiście korzystałem z Pythona do celów naukowych o nazwie Anaconda (ze świetnym instalatorem pakietów conda. Można też spróbować zainstalować gotowy pakiet stąd.

Kopalnia współrzędnych

Przy zaledwie czterech punktach na mapie współrzędne można oczywiście wygrzebać z Wikipedii. Gdyby jednak trzeba ich było znaleźć więcej, to polecam plik Excela z Państwowego Rejestru Nazw Geograficznych (plik można legalnie i nieodpłatnie pobrać tutaj, sprawdźcie tylko, czy nie ma jakichś ograniczeń licencyjnych).

Tabela zawiera w tej chwili 265092 nazw geograficznych (np. miast, wsi i ich części) oraz ich współrzędnych. Jest to na tyle ciekawy zbiór, że zasługuje na osobną notkę; mam nadzieję, że ukaże się ona przed kolejnym Sylwestrem.

Uwaga techniczna: współrzędne, zarówno w Wikipedii jak i w pliku PRNG są podane w stopniach i minutach kątowych (np. 51°22'18'' N), więc trzeba je przeliczyć na ułamki dziesiętne (51+22/60+18/3600 = 51.3716666666667). W tym zapisie półkulę południową i zachodnią przedstawia się przy użyciu liczb ujemnych.

Rysujemy mapę

Po zaimportowaniu wszystkich potrzebnych pakietów, możemy zabrać się za rysowanie mapy. Kolejna linia, rozbita na części ze względu na czytelność, zawiera sporo parametrów:
  • projection (odwzorowanie) – tutaj będzie to stary dobry Mercator
  • lat_0 – w tym odwzorowaniu: szerokość geograficzna środkowego równoleżnika
  • lon_0 – w tym odwzorowaniu: długość geograficzna środkowego południka
  • resolution – rozdzielczość high (czyli wysoka, może być też 'l' (low = niska) czy 'c' (crude = toporna)
  • area_thresh to parametr oznaczający jakie obiekty mają być pominięte (tutaj – wszystkie obiekty o powierzchni poniżej 150 km2)
  • llcrnrlon i llcrnrlat to odpowiednio długość i szerokość geograficzna lewego dolnego rogu (lower left corner) mapy, a urcrnrlon i urcrnrlat to długość i szerokość geograficzna jej prawego górnego rogu (upper right corner).


Czas na kropki

Do narysowania punktów i miejscowości potrzebne są trzy listy: z długościami geograficznymi naszych miast, z szerokościami no i z nazwami (etykietami).

W linii 14 program przelicza dane z listy na współrzędne na rysunku, a w następnej rysuje punkty.

W kolejnych liniach program wstawia nazwy miast. Etykiety nie mogą być w tym samym miejscu, co punkty, stąd przesunięcie (podawane, co ciekawe, w metrach): -80000 dla współrzędnej x i +22000 dla współrzędnej y.

Tak naprawdę ciężko jest znaleźć jedno i takie samo optymalne przesunięcie dla wszystkich nazw – powinno ono być inne dla każdego napisu i umieszczone w postaci oddzielnej listy. Problem ten dość ładnie rozwiązano na blogu peak 5390, który był dla mnie sporą pomocą i inspiracją w trakcie pisania tej notki.

Kolorowanie

Kolejne linie programu to polecenia do rysowania wybrzeży (drawcoastlines), granic państwowych (drawcountries, tutaj z opcjonalnie podanym kształtem przerywanych kresek), wreszcie wypełnienia lądów (fillcontinents) i mórz (drawmapboundary).

Oprócz poetyckich nazw kolorów istnieje możliwość wpisania ich numeru RGB. Dodatkowo, kasując linijki i wstawiając odpowiednie polecenie, można stworzyć tło z danych satelitarnych – w stylu mapy Google (bluemarble), tradycyjnej mapy topograficznej (etopo) czy cieniowanej rzeźby terenu (shadedrelief).

Z góry jednak uprzedzam, że tego rodzaju tła w tej skali wyglądają dość mizernie.


Tło ze zdjęć satelitarnych jest dość niewyraźne;



na mapie topograficznej widać wręcz kwadratowe ,,kafelki"...



...a cieniowana rzeźba terenu jest mocno uproszczona (gdzie jest Pas Wyżyn?).


Tego rodzaju tło dużo lepiej sprawdza się w przypadku mapy świata:



Dla ciekawych – kod programu (8 linijek!):



Inna sprawa, że generowanie takiego tła może nam strasznie spowolnić komputer. To chyba największa wada pakietu Basemap – python nie należy do najszybszych języków programowania, a ilość obliczeń, jakich musi tutaj dokonać, jest spora. Zwykła mapa potrafi zatkać komputer na pół minuty, natomiast czas rysowania cieniowanej rzeźby terenu niekiedy jest dłuższy od bloku reklamowego na Polsacie.

Skoro zacząłem już o wadach – nie wiedzieć czemu, polecenie do rysowania podziałki nie działa w każdym odwzorowaniu, co gorsza, programista nie dostaje nawet najmniejszego ostrzeżenia w tej sprawie.

Zapis mapy

Ostatnia linia programu służy do zapisu – format docelowy rysunku (SVG, PNG, JPEG, PDF) program automatycznie rozpoznaje na podstawie rozszerzenia pliku.

Szczęśliwego Nowego Roku!

2 komentarze:

Agata Borowska pisze...

Ciekawie opisane. Czekam na jeszcze więcej.

Monika Zawadzka pisze...

Bardzo ciekawie napisane. Super wpis. Pozdrawiam serdecznie.