Scott Tiger Tech Blog

Blog technologiczny firmy Scott Tiger S.A.

Konwersja Shapefile do SVG

Autor: Piotr Karpiuk o wtorek 7. Marzec 2017

Na stronach webowych nieraz chciałoby się pozwolić użytkownikowi wskazać myszką jakiś obszar geograficzny (państwo, województwo, gmina) na uproszczonej mapie, jak poniżej:

Taka interakcja znajduje zastosowanie we wszelkiego rodzaju wizualizacjach danych, menu witryny, formularzach itp.

W dzisiejszych czasach stosowną do tego technologią jest grafika wektorowa, w praktyce: SVG.

Problemem, którym się dziś zajmiemy jest odpowiedź na pytanie skąd wziąć dane wektorowe i jak je przekształcić do użytecznej postaci (czytaj: niewielkiego pliku SVG).

Polska
Dane wektorowe granic: kraju, województw, powiatów, gmin (ale też prokuratur, sądów, komend policji, urzędów skarbowych, rejonów statystycznych, nadleśnictw itp.) znajdziemy w witrynie Centralnego Ośrodka Dokumentacji Geodezyjnej i Kartograficznej (CODGiK) na stronie Dane bez opłat – chodzi o tzw. Państwowy Rejestr Granic (PRG).
Świat
Tutaj polecam witrynę NaturalEarth, z której możemy zaciągnąć m.in. granice wektorowe wszystkich państw, ale też np. strefy czasowe, parki narodowe itp.

Standardem dla „danych wektorowych” w praktyce jest format shapefile.

Do konwersji plików *.shp/dbf na *.svg polecam program Mapshaper.

Najpierw orientujemy się w strukturze pliku:

mapshaper gminy.shp encoding=win1250 -info

Parametr encoding informuje jakiego kodowania znaków użyto w pliku gminy.dbf. W wyniku otrzymujemy:

[info] 
Layer 1
Layer name: gminy
Records: 2,478
Geometry
  Type: polygon
  Bounds: 171677.555189595 133223.725152462 861895.746988281 774923.7474734206
  Proj.4: +proj=tmerc +x_0=500000 +y_0=-5300000 +lon_0=19 +k_0=0.9993 +ellps=GRS80
Attribute data
  Field       First value
  gra_ids     ''
  id_bufor01  13846
  id_bufora_      0
  id_technic      0
  iip_identy  '4ed7022d-98d4-4d77-a669-d991d57b76c2'
  iip_przest  'PL.PZGIK.200'
  iip_wersja  '2012-09-26T22:31:18+02:00'
  jpt_jor_id      0
  jpt_kj_i01  '0222033'
  jpt_kj_i02  ''
  jpt_kj_iip  '0000000000EGIB'
  jpt_kod_01  ''
  jpt_kod_je  '0222033'
  jpt_nazw01  ''
  jpt_nazwa_  'Wołów'
  jpt_opis    '827772'
  jpt_orga01  'NZN'
  jpt_organ_  ''
  jpt_powier     26
  jpt_sjr_ko  'GMI'
  jpt_sps_ko  'UZG'
  jpt_wazna_  '6        NZN'
  opis_bledu  ''
  status_obi  'AKTUALNY'
  typ_bledu   ''
  wazny_do    "1899-12-30T00:00:00.000Z"
  wazny_od    "1899-11-30T00:00:00.000Z"
  wersja_do   "2020-12-09T00:00:00.000Z"
  wersja_od   "1899-11-30T00:00:00.000Z"

Jak widać, mamy układ współrzędnych GRS80, a interesujące pola to jpt_nazwa_ (nazwa gminy) i jpt_kod_je (kod TERYT gminy).

Konwersja pliku gminy.shp z CODGiKu może wyglądać tak:

mapshaper gminy.shp \
  encoding=win1250 
  -svg-style stroke=black stroke-width=2 fill=lightgray \
  -simplify resolution=3840x2160 \
  -o pl-gminy.svg \
  width=3840 \
  id-field=jpt_kod_je

W wyniku otrzymamy plik pl-gminy.svg o postaci:

<?xml version="1.0"?>
<svg xmlns="http://www.w3.org/2000/svg" version="1.2" baseProfile="tiny"
   width="3840" height="3571" viewBox="0 0 3840 3571" stroke-linecap="round" stroke-linejoin="round">
  <g id="pl-gminy">
    <path d="M 825.0477 2175.5108 827.1395 2173.3412 831.036 2168.2329 ... 825.0477 2175.5108 Z" 
      stroke="black" stroke-width="2" fill="lightgray" id="0222033"/>
    ...
  </g>
</svg>

Jak widzimy, mamy tu po jednym elemencie <path> dla każdej gminy, z atrybutem id będącym kodem TERYT (dokładniej: TERC) tej gminy. (Uwaga: plik XML z rekordami bazy TERYT każdego województwa/powiatu/gminy można pobrać ze strony teryt.stat.gov.pl). Dodatkowo poprosiliśmy też o uproszczenie kształtu każdego wielokąta tak by jednak wyglądał przyzwoicie nawet na monitorach 4K (3840×2160), dzięki czemu wynikowy plik ma ok. 5 MB (źródłowy SHP miał 81 MB).

A gdybyśmy chcieli „wyciąć” sobie pojedynczą gminę? Wystarczy dodać filtr z kodem TERC gminy (zaraz po parametrze encoding):

-filter 'jpt_kod_je=="0222033"'

Gmina Wołów o kodzie TERC 0222033 wygląda tak:

Czasami okazuje się, że plik shapefile używa układu odniesienia innego niż chcemy. Np. dane z serwisu EarthData używają na ogół układu EPSG:4326 (WGS84, GPS), a może chcielibyśmy żeby obszary wyglądały jak w Google Maps (EPSG:3857, Spherical Mercator). W Linuksie możemy użyć polecenia ogr2ogr (biblioteka GDAL).

ogr2ogr -t_srs EPSG:3857 google-maps-world.shp earth-data-countries.shp

Powiedzmy że ze wszystkich państw świata interesuje nas tylko Ameryka Południowa:

mapshaper google-maps-world.shp -filter 'CONTINENT == "South America"' \
  -svg-style stroke=black stroke-width=1 fill=lightblue \
  -simplify resolution=3840x2160 -o africa.svg \
  width=700 id-field=NAME

Share and Enjoy:
  • del.icio.us
  • Facebook
  • Google Bookmarks
  • Śledzik
  • Blip
  • Blogger.com
  • Gadu-Gadu Live
  • LinkedIn
  • MySpace
  • Wykop

Zostaw komentarz

XHTML: Możesz użyć następujących tagów: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>