Implementace skriptu pro GRASS¶
Skript bude v první fázi vypisovat pro dané PSČ seznam obcí a jejich sousedy dle PSČ.
Příprava dat¶
Vektorová mapa obce_polygon z mapsetu ruian neobsahuje v atributové tabulce PSČ. Tuto informaci budeme muset nejprve doplnit. PSČ obcí ke stažení zde jako DBF tabulka.
V aktuálním mapsetu si vytvoříme kopii původní mapy (g.copy) a k její atributové tabulce připojíme tabulku s PSČ.
g.copy vector=obce_polygon@ruian,obce
Vstupní tabulku s PSČ nejprve pomocí db.in.ogr naimportujeme:
db.in.ogr input=zv_pcobc.dbf encoding=cp852
Poznámka
Modul předpokládá kódování znaků UTF-8. Vzhledem k tomu, že
jsou vstupní data v kódování CP852 (DOS), je nutné jej definovat
parametrem encoding
.
Ve verzích GRASS 7.0.2 a nižší modul db.in.ogr
parametr encoding
nemá. V tomto případě definujeme
kódování pomocí proměnné prostředí
SHAPE_ENCODING
.
SHAPE_ENCODING=cp852 db.in.ogr input=zv_pcobc.dbf
Tabulka bohužel neobsahuje kód obce, podle kterého bysme mohli data pohodlně pomocí modulu v.db.join připojit k atributové tabulce obcí, viz. výpis modulu db.select.
db.select sql="select * from zv_pcobc_dbf limit 1"
NAZCOBCE|PSC|NAZPOST|KODOKRESU|NAZOKRESU|NAZOBCE|KOD
Abertamy|36235|Abertamy|3403|Karlovy Vary|Abertamy|
Vytvoříme pomocnou tabulku pomocí db.execute, která bude obsahovat dva sloupce: kód obce a PSČ.
db.execute sql="create table obce_psc as select o.kod,z.psc from obce as o join zv_pcobc_dbf as z on o.okreskod = z.KODOKRESU and o.nazev = z.NAZOBCE"
Poznámka
Tento postup je nutný, neboť databáze SQLite (která je pro systém GRASS vychozí při ukládání atributových dat, viz školení pro začátečníky), nepodporuje JOIN v příkazu UPDATE. Pokud používate namísto toho např. PostgreSQL, tak se operace zjednoduší.
Takto vytvořenou tabulku již lze k atributové tabulce vektorové mapy obcí pomocí v.db.join připojit.
v.db.join map=obce column=kod other_table=obce_psc other_column=kod
Výsledek si můžeme zkontrolovat pomocí modulu v.db.select.
v.db.select map=obce column=kod,nazev,psc
...
532401|Jarpice|27371
532428|Jemníky|27401
548103|Kámen|39413
...
Implementace testovací verze skriptu¶
Podrobnější informace v kapitole Přístup k vektorovým datům.
1#!/usr/bin/env python3
2
3from grass.pygrass.vector import VectorTopo
4
5psc = '41115'
6
7obce = VectorTopo('obce')
8obce.open('r')
9
10print("Seznam obci s PSC {}:".format(psc))
11obce_psc = set()
12for prvek in obce.viter('areas'):
13 if prvek.attrs is None or prvek.attrs['psc'] != psc:
14 continue
15 obce_psc.add(prvek.id)
16 print("{0}: {1}".format(psc, prvek.attrs['nazev']))
17
18sousede = set()
19for prvek in obce.viter('areas'):
20 if prvek.id not in obce_psc:
21 continue
22
23 for b in prvek.boundaries():
24 for n in b.read_area_ids():
25 if n != -1 and n != prvek.id:
26 sousede.add(n)
27
28print("Seznam sousednich obce:")
29for prvek in obce.viter('areas'):
30 if prvek.id not in sousede or \
31 prvek.attrs['psc'] == psc:
32 continue
33
34 print("{0}: {1}".format(prvek.attrs['psc'], prvek.attrs['nazev']))
35
36obce.close()
Poznámka
Skript je koncipován jako ukázka, uvedená implementace má vážné nedostatky, např. nepoužívá vůbec prostorový index. Místo toho všechny prvky prochází sekvenčně.
Skript ke stažení zde.
Výstup může vypadat následovně:
Seznam obci s PSC 41115:
41115: Děčany
41115: Podsedice
41115: Jenčice
41115: Lkáň
41115: Chodovlice
41115: Dlažkovice
41115: Sedlec
41115: Třebívlice
Seznam sousednich obce:
44001: Želkovice
41002: Velemín
41113: Třebenice
41804: Lukov
41002: Úpohlavy
41002: Slatina
41114: Vlastislav
43921: Koštice
43922: Chožov
43926: Libčeves
41002: Vchynice
41002: Čížkovice
41116: Klapý
41113: Třebenice
41757: Hrobčice
Druhá verze skriptu¶
Druhá verze skriptu se bude lišit od první tím, že namísto textového výpisu vytvoří novou vektorovou mapu se spojeným polygonem obcí s definovaným PSČ a zároveň bude obsahovat sousední obce.
1#!/usr/bin/env python3
2
3from grass.pygrass.vector import VectorTopo
4
5psc = '41115'
6
7obce = VectorTopo('obce')
8obce.open('r')
9
10vystup = VectorTopo('obce_psc_{}'.format(psc))
11vystup.open('w', tab_cols=[('cat', 'INTEGER PRIMARY KEY'),
12 ('nazev', 'TEXT'),
13 ('psc', 'INTEGER')])
14
15obec_id = None
16obce_psc = set()
17for prvek in obce.viter('areas'):
18 if prvek.attrs is None:
19 continue
20 if prvek.attrs['psc'] == psc:
21 if obec_id is None:
22 obec_id = prvek.id
23
24 for b in prvek.boundaries():
25 for n in b.read_area_ids():
26 if n != -1 and n != obec_id:
27 obce_psc.add(n)
28obce_psc.add(obec_id)
29
30hranice = list()
31for prvek in obce.viter('areas'):
32 if prvek.id not in obce_psc:
33 continue
34
35 for b in prvek.boundaries():
36 if b.id not in hranice:
37 hranice.append(b.id)
38 vystup.write(b, attrs=(None, None))
39
40 vystup.write(prvek.centroid(), attrs=(prvek.attrs['nazev'], prvek.attrs['psc']))
41
42vystup.table.conn.commit()
43
44vystup.close()
45obce.close()
Skript ke stažení zde.
Poznámka¶
Úloha by se dala samozřejmě řešit poměrně jednoduše namísto PyGRASS kombinací standardních modulů systému GRASS v.extract a v.select.
1#!/usr/bin/env python3
2
3from grass.pygrass.modules import Module
4
5psc = '41115'
6
7Module('v.extract', input='obce', output='obce1',
8 where="psc = '{}'".format(psc))
9Module('v.select', ainput='obce', binput='obce1',
10 output='obce_psc_{}'.format(psc),
11 operator='overlap', overwrite=True)
12Module('g.remove', type='vector', name='obce1', flags='f')
Skript ke stažení zde.