GRASS GIS / Skriptování / Uživatelský vstup

Z FreeGIS portál
Přejít na: navigace, hledání

Tato stránka uvádí možnosti implementace uživatelského vstupu do skriptů pro systém GRASS GIS.

Jako příklad použijeme skript ndvi.py. Tento skript má dva vstupní parametry - název rastrové mapy 3. a 4. kanálu družicové scény Landsat 5 (TM).

 8 ...
 9 # nastavit region
10 g.region(rast='tm4')
11 
12 # vypocitat NDVI
13 r.mapcalc('ndvi = float(tm4 - tm3) / (tm4 + tm3)', overwrite = True)
14 ...

ndvi

Vstup v podobě uživatelem zadaných parametrů obsahuje systémová proměnná sys.argv. Jednoduchou úpravou skriptu dovolíme uživateli nastavení vstupních rastrových map jako parametry skriptu.

 8 ...
 9 # prvni prvek seznamu sys.argv[0] obsahuje nazev skriptu
10 tm3 = sys.argv[1]
11 tm4 = sys.argv[2]
12 
13 # nastavit region
14 g.region(rast=tm3)
15 
16 # vypocitat NDVI
17 r.mapcalc('ndvi = float(' + tm4 + '-  ' + tm3 + ') / (' + tm4 + ' + ' + tm3 + ')', overwrite = True)
18 ...

Note Poznámka: Řádek 17 je efektivnější přepsat pomocí substituce

16 ...
17 r.mapcalc('ndvi = float({y} - {x}) / ({y} + {x})'.format(x=tm3, y=tm4), overwrite = True)
18 ...

anebo

16 ...
17 r.mapcalc('ndvi = float(%s - %s) / (%s + %s)' % (tm4, tm3, tm4, tm3), overwrite = True)
18 ...

Příklad spuštění skriptu

~/bin/grass/ndvi.py tm3 tm4

Ve skriptu není ošetřen chybový stav, kdy nejsou uživatelem definovány potřebné vstupní parametry, např.

~/bin/grass/ndvi.py
Traceback (most recent call last):
  File "./ndvi-v1.py", line 9, in <module>
    tm3 = sys.argv[1]
IndexError: list index out of range

Do skriptu přidáme test počtu zadaných parametrů.

 8 ...
 9 if len(sys.argv) != 3:
10     sys.exit("Skript vyzaduje dva parametry - nazev 3. a 4. kanalu TM")
11 
12 # prvni prvek seznamu sys.argv[0] obsahuje nazev skriptu
13 tm3 = sys.argv[1]
14 tm4 = sys.argv[2]
15 ...
~/bin/grass/ndvi.py
Skript vyzaduje dva parametry - nazev 3. a 4. kanalu TM

Výsledkem je nová verze skriptu

Výpočet NDVI jako skript v jazyce Python (ke stažení jako ndvi-v2)
 1 #!/usr/bin/env python
 2 
 3 import sys
 4 
 5 from grass.pygrass.modules.shortcuts import general as g
 6 from grass.pygrass.modules.shortcuts import raster as r
 7 
 8 if len(sys.argv) != 3:
 9     sys.exit("Skript vyzaduje dva parametry - nazev 3. a 4. kanalu TM")
10 
11 # prvni prvek seznamu sys.argv[0] obsahuje nazev skriptu
12 tm3 = sys.argv[1]
13 tm4 = sys.argv[2]
14 
15 g.message("Pocitam NDVI...")
16 
17 # nastavit region
18 g.region(rast=tm4)
19 
20 # vypocitat NDVI
21 r.mapcalc('ndvi = float({y} - {x}) / ({y} + {x})'.format(x=tm3, y=tm4), overwrite = True)
22 
23 # r.reclass podporuje pouze datovy typ CELL
24 r.mapcalc('temp1 = 100 * ndvi', overwrite = True)
25 g.message("Reklasifikuji data...")
26 
27 # reklasifikovat data
28 reclass_rules = """-100 thru 5   = 1 bez vegetace, vodni plochy
29 5   thru 35  = 2 plochy s minimalni vegetaci
30 35  thru 100  = 3 plochy pokryte vegetaci"""
31 r.reclass(overwrite = True, rules = '-',
32           input = 'temp1', output = 'r_ndvi', stdin_ = reclass_rules)
33 
34 # nastavit tabulku barev
35 color_rules = """1 red
36 2 yellow
37 3 0 136 26"""
38 r.colors(quiet = True,
39          map = 'r_ndvi', rules = '-', stdin_ = color_rules)
40 
41 # vytiskout zakladni charakteristiku dat 
42 r.report(map = 'r_ndvi', units = ['c', 'p', 'h'])

i.ndvi

GRASS obsahuje mechanismus pro generování GUI dialogu pro jednotlivé příkazy či uživatelské skripty. Rozhraní se definuje na začátku skriptu v podobě speciálních komentářů začínajících na znaky #%.

Např.

#%module
#% description: Vypocet NDVI
#%end
#%option G_OPT_R_INPUT
#% key: tm3
#% description: Treti kanal Landsat TM
#%end
#%option G_OPT_R_INPUT
#% key: tm4
#% description: Ctvrty kanal Landsat TM
#%end

definuje

  • popis skriptu
  • dva parametry tm3 a tm4 pro vstup rastrových map
~/bin/grass/ndvi.py --help
Description:
 Vypocet NDVI

Usage:
 ndvi-v1.py tm3=name tm4=name [--verbose] [--quiet]

Flags:
 --v   Verbose module output
 --q   Quiet module output

Parameters:
  tm3   Treti kanal Landsat TM
  tm4   Ctvrty kanal Landsat TM

Spuštěním skriptu bez parametrů získáme GUI dialog, který umožňuje vstupní parametry definovat interaktivně.

GUI dialog skriptu pro výpočet NDVI
Výpočet NDVI v GUI dialogu

Výpočet přesuneme do funkce main(), funkce parseru je dostupná v balíčku grass.script, celý skript viz níže.

Výpočet NDVI jako skript v jazyce Python (ke stažení jako i.ndvi-v1)
 1 #!/usr/bin/env python
 2 
 3 #%module
 4 #% description: Vypocet NDVI
 5 #%end
 6 #%option G_OPT_R_INPUT
 7 #% key: tm3
 8 #% description: Treti kanal Landsat TM
 9 #%end
10 #%option G_OPT_R_INPUT
11 #% key: tm4
12 #% description: Ctvrty kanal Landsat TM
13 #%end
14 
15 import sys
16 
17 from grass.pygrass.modules.shortcuts import general as g
18 from grass.pygrass.modules.shortcuts import raster as r
19 
20 import grass.script as grass
21 
22 def main():
23     g.message("Pocitam NDVI...")
24 
25     # nastavit region
26     g.region(rast=options['tm4'])
27     
28     # vypocitat NDVI
29     r.mapcalc('ndvi = float({y} - {x}) / ({y} + {x})'.format(x=options['tm3'], y=options['tm4']), overwrite = True)
30     
31     # r.reclass podporuje pouze datovy typ CELL
32     r.mapcalc('temp1 = 100 * ndvi', overwrite = True)
33     g.message("Reklasifikuji data...")
34     
35     # reklasifikovat data
36     reclass_rules = """-100 thru 5   = 1 bez vegetace, vodni plochy
37 5   thru 35  = 2 plochy s minimalni vegetaci
38 35  thru 100  = 3 plochy pokryte vegetaci"""
39     r.reclass(overwrite = True, rules = '-',
40               input = 'temp1', output = 'r_ndvi', stdin_ = reclass_rules)
41     
42 # nastavit tabulku barev
43     color_rules = """1 red
44 2 yellow
45 3 0 136 26"""
46     r.colors(quiet = True,
47              map = 'r_ndvi', rules = '-', stdin_ = color_rules)
48     
49     # vytiskout zakladni charakteristiku dat 
50     r.report(map = 'r_ndvi', units = ['c', 'p', 'h'])
51 
52 if __name__ == "__main__":
53     options, flags = grass.parser()
54     main()

i.ndvi (kontrola vstupu, cleanup)

Skript vylepšíme o kontrolu vstupu, implementuje funkci check_map(), která ověří zda je rastrová mapa dostupná ve vyhledávací cestě.

from grass.pygrass.functions import get_mapset_raster
...
def check_map(map_name):
    mapset = get_mapset_raster(map_name)
    if not mapset:
        sys.exit("Raster map <%s> not found" % map_name)
    
    if '@' not in map_name:
        map_name += '@' + mapset
    
    return map_name

def main():
    tm3 = check_map(options['tm3'])
    tm4 = check_map(options['tm4'])
    ...
    g.message("Pocitam NDVI...")
    # nastavit region
    g.region(rast=tm3)
    
    # vypocitat NDVI
    r.mapcalc('ndvi = float({y} - {x}) / ({y} + {x})'.format(x=tm3, y=tm4), overwrite = True)

Dále definuje funkci cleanup(), která odstraní všechny rastrové mapy označené jako přechodné.

from grass.pygrass.functions import get_mapset_raster, remove

def cleanup():
    for map in TMP_MAPS:
        remove(map, 'rast')

Abychom zajistili, že se tato funkce spustí i v případě chyby či přerušení běhu skriptu uživatelem, tak tuto funkci zaregistrujeme pomocí atexit.

import atexit
...
if __name__ == "__main__":
...
    atexit.register(cleanup)
...

Skript upravíme tak, že všechny vytvořené rastrové mapy budou přechodné a budou po ukončení skriptu smazány.

import os
...
def main():
...
    # definovat nazvy pro prechodne mapy
    ndvi = 'ndvi_%s' % os.getpid()
    ndvi100 = 'ndvi100_%s' % os.getpid()
    ndvi_rekl = 'ndvi_rekl_%s' % os.getpid()
...
    r.mapcalc('{z} = float({y} - {x}) / ({y} + {x})'.format(x=tm3, y=tm4, z=ndvi), overwrite = True)
...
    r.mapcalc('{x} = 100 * {y}'.format(x=ndvi100, y=ndvi), overwrite = True)
...
    r.reclass(overwrite = True, rules = '-',
              input = ndvi100, output = ndvi_rekl, stdin_ = reclass_rules)
...
    r.colors(quiet = True,
             map = ndvi_rekl, rules = '-', stdin_ = color_rules)
...    
    # vytiskout zakladni charakteristiku dat 
    r.report(map = ndvi_rekl, units = ['c', 'p', 'h'])
...
    # definovat mapy jako prechodne
    global TMP_MAPS
    TMP_MAPS = [ndvi, ndvi_rekl, ndvi100]

Nakonec přidáme nový parametr output umožňující definovat název pro výstupní rastrové mapy. Pokud uživatel definuje název výstupní mapy, tak NDVI nebude zařazena mezi přechodné mapy určené ke smazání.

#%option G_OPT_R_OUTPUT
#% description: Nazev pro vystupni NDVI
#% required: no
#%end
...
def main():
...
    # definovat nazvy pro prechodne mapy
    if options['output']:
        ndvi = options['output']
    else:
        ndvi = 'ndvi_%s' % os.getpid()
    ndvi100 = 'ndvi100_%s' % os.getpid()
    ndvi_rekl = 'ndvi_rekl_%s' % os.getpid()
...
    # definovat mapy jako prechodne
    global TMP_MAPS
    TMP_MAPS = [ndvi_rekl, ndvi100]
    if not options['output']:
        TMP_MAPS.append(ndvi)
...

Výsledný skript je ke stažení zde.