Unit 12 - Script tuning

In Unit 10 - Python intro and Unit 11 - Scripting we gain basic knowledge of GRASS Scripting Library, we know how to run GRASS modules using different functions (core.run_command, core.read_command, and core.parse_command). We are also able to parse module output in simply way. Beside core package the GRASS Scripting Library also offers useful functions which can simplify our scripts.

  • db Database related functions
  • raster Raster related functions
  • raster3d Raster3d related functions
  • vector Vector related functions

In our case we could replace v.db.select caller by vector.vector_db_select function. In other worlds replace code below

# v.db.select: don't print column names (-c)
ret = read_command('v.db.select', flags='c', map='ndvi_vector', separator='comma')
for line in ret.splitlines():
    # parse line (eg. 1,,-0.433962264150943,0.740350877192983,0.051388909449992)
    cat,label,min,max,mean = line.split(',')
    print ('NDVI class {0}: {1:.4f} (min) {2:.4f} (max) {3:.4f} (mean)'.format(
    cat, float(min), float(max), float(mean)))

by

from grass.script.vector import vector_db_select
data = vector_db_select('ndvi_vector')
for vals in data['values'].itervalues():
    # unfortunately we need to cast values by float
    print ('NDVI class {0}: {1:.4f} (min) {2:.4f} (max) {3:.4f} (mean)'.format(
    vals[0], float(vals[2]), float(vals[3]), float(vals[4])))

There is one problem with our script, some modules (r.recode, r.colors) uses hardcoded path to input files. This will not work when running script on different computer as we know. See code below (concretely rules options).

run_command("r.recode",
            overwrite = True,
            input = "ndvi",
            output = "ndvi_class",
            rules = "/home/landa/geodata/jena/models/reclass.txt")

run_command("r.colors",
            map = "ndvi_class",
            rules = "/home/landa/geodata/jena/models/colors.txt")

By GRASS Scripting Library we can define content of input file as a string object and transfer it to the command via standard input. This operation is allowed by core.feed_command function.

    p1 = feed_command("r.recode",
                      overwrite = True,
                      input = "ndvi",
                      output = "ndvi_class",
                      rules = "-")
    p1.stdin.write("""-1:0.1:1
0.1:0.5:2
0.5:1:3""")
    p1.stdin.close()
    p1.wait()

    p2 = feed_command("r.colors",
                      map = "ndvi_class",
                      rules = "-")
    p2.stdin.write("""1 grey
2 255 255 0
3 green""")
    p2.stdin.close()
    p2.wait()

First a command object is created, input string written to stdin, closed and than the command finally performed by wait().

We can also define cleanup routine which removes all intermediate data when compution is finished.

def cleanup():
    run_command('g.remove', flags='f', name='region_mask', type='vector')

User input

Our script lacks user input, all the input paramaters are hardcoded. We have to modify our script similarly as we did for model Unit 09 - Model tuning. Do you remember our first modification of model in Unit 11 - Scripting?

Let’s add previously removed lines back to the script.

#%module
#% description: NDVI model version 2
#%end

After running a script, a magic is done, and GUI dialog appears. This dialog was generated from few lines above. Since we defined only module description and no parameters, the dialog offers only global flags like –verbose or –quiet.

../_images/ndvi-dialog.png

Fig. 81 Generated GUI dialog of our script.

Let’s define few parameters:

  • region: vector map defining a region (required)
  • clouds: vector map with cloud mask features (optional)
  • red: input red channel (required)
  • nir: input nir channel (required)
  • threshold: threshold for removing small areas (optional)
  • basename: basename for output maps (required)

Related lines can look like as below.

#%option G_OPT_V_INPUT
#% key: region
#% description: Name of input vector region map 
#%end
#%option G_OPT_V_INPUT
#% key: clouds
#% description: Name of input vector clouds map 
#% required: no
#%end
#%option G_OPT_R_INPUT
#% key: red
#% description: Name of input red channel
#%end
#%option G_OPT_R_INPUT
#% key: nir
#% description: Name of input NIR channel
#%end
#%option
#% key: threshold
#% description: Threshold for removing small areas
#% answer: 1600
#%end
#%option G_OPT_V_OUTPUT
#%end
../_images/ndvi-dialog-params.png

Fig. 82 GUI dialog including input options.

In the script we have still input parameters hardcoded, eg.

run_command("v.overlay",
            overwrite = True,
            ainput = "jena_boundary@PERMANENT",
            binput = "MaskFeature@PERMANENT",
            operator = "not",
            output = "region_mask")

The input parameters are accesible by options and flags objects which are generated by parse() function.

options, flags = parser()

Options and flags are dictionaries, where parameters are accessible by option keys, see example below.

run_command("v.overlay",
            overwrite = True,
            ainput = options["region"],
            binput = options["clouds"],
            operator = "not",
            output = "region_mask")

The clouds option is not mandatory, so we will perform v.overlay module only when this option is given.


    if options["clouds"]:
        region_mask = "region_mask"
        run_command("v.overlay",
                    overwrite = True,
                    ainput = options["region"],
                    binput = options["clouds"],
                    operator = "not",
                    output = region_mask)
    else:
        region_mask = options["region"]

    run_command("g.region",
                overwrite = True,
                vector = region_mask,

All other generated maps will be removed when computation finished.

def cleanup():
    run_command('g.remove', flags='f', name='region_mask', type='vector')
    run_command('g.remove', flags='f', name='ndvi', type='raster')
    run_command('g.remove', flags='f', name='ndvi_class', type='raster')
    run_command('g.remove', flags='f', name='ndvi_class', type='vector')
../_images/call-ndvi-script.png

Fig. 83 NDVI script in action.

Sample script to download: ndvi-v3.py