Exemple #1
0
    def load_map(self):
	run('g.region', **self.wind)

	p = grass.pipe_command('r.out.ascii', input = self.inmap, quiet = True)
	self.wind = self.read_header(p.stdout)
	self.values = self.read_data(p.stdout)
	self.changed = [[False for c in row] for row in self.values]
	p.wait()

	self.clear_changes()

	run('r.out.ppm', input = self.inmap, output = self.tempfile)
	colorimg = wx.Image(self.tempfile)
	grass.try_remove(self.tempfile)

	for row in range(self.wind['rows']):
	    for col in range(self.wind['cols']):
		val = self.values[row][col]
		if val in self.colors:
		    continue
		r = colorimg.GetRed(col, row)
		g = colorimg.GetGreen(col, row)
		b = colorimg.GetBlue(col, row)
		color = "#%02x%02x%02x" % (r, g, b)
		self.colors[val] = color

	colorimg.Destroy()
Exemple #2
0
        def load_map(self):
            run("g.region", **self.wind)

            p = grass.pipe_command("r.out.ascii", input=self.inmap, quiet=True)
            self.wind = self.read_header(p.stdout)
            self.values = self.read_data(p.stdout)
            self.changed = [[False for c in row] for row in self.values]
            p.wait()

            self.clear_changes()

            run("r.out.ppm", input=self.inmap, output=self.tempfile)
            colorimg = wx.Image(self.tempfile)
            grass.try_remove(self.tempfile)

            for row in range(self.wind["rows"]):
                for col in range(self.wind["cols"]):
                    val = self.values[row][col]
                    if val in self.colors:
                        continue
                    r = colorimg.GetRed(col, row)
                    g = colorimg.GetGreen(col, row)
                    b = colorimg.GetBlue(col, row)
                    color = "#%02x%02x%02x" % (r, g, b)
                    self.colors[val] = color

            colorimg.Destroy()
Exemple #3
0
    def load_aspect(self):
	if not self.aspect:
	    return

	p = grass.pipe_command('r.out.ascii', input = self.aspect, quiet = True)
	self.read_header(p.stdout)
	self.angles = self.read_data(p.stdout)
	p.wait()
Exemple #4
0
    def load_aspect(self):
        if not self.aspect:
            return

        p = grass.pipe_command('r.out.ascii', input=self.aspect, quiet=True)
        self.read_header(p.stdout)
        self.angles = self.read_data(p.stdout)
        p.wait()
Exemple #5
0
def get_nr_of_categories(vector, layer, rasters, rastertmp, percentile,
                         colprefixes, basecols, dbfdriver, c):
    """Get number of raster categories to be processed.

    Perform also checks of raster and vector categories. In the case of no
    raster categories, create the desired columns and exit.

    :param vector: name of vector map or data source for direct OGR access
    :param layer: layer number or name
    :param rastertmp: name of temporary raster map
    :return: number of raster categories or exit (if no categories found)
    """
    # dump cats to file to avoid "too many argument" problem:
    p = grass.pipe_command("r.category", map=rastertmp, sep=";", quiet=True)
    cats = []

    for line in p.stdout:
        line = decode(line)
        cats.append(line.rstrip("\r\n").split(";")[0])
    p.wait()

    number = len(cats)
    if number < 1:
        # create columns and exit
        grass.warning(_("No categories found in raster map"))
        for i in range(len(rasters)):
            set_up_columns(
                vector,
                layer,
                percentile,
                colprefixes[i],
                basecols,
                dbfdriver,
                flags["c"],
            )
            sys.exit(0)

    # Check if all categories got converted
    # Report categories from vector map
    vect_cats = (grass.read_command("v.category",
                                    input=vector,
                                    option="report",
                                    flags="g").rstrip("\n").split("\n"))

    # get number of all categories in selected layer
    vect_cats_n = 0  # to be modified below
    for vcl in vect_cats:
        if vcl.split(" ")[0] == layer and vcl.split(" ")[1] == "all":
            vect_cats_n = int(vcl.split(" ")[2])

    if vect_cats_n != number:
        grass.warning(
            _("Not all vector categories converted to raster. \
                        Converted {0} of {1}.".format(number, vect_cats_n)))

    return number
Exemple #6
0
def copy_colors(fh, map, offset):
    p = gscript.pipe_command('r.colors.out', map=map)
    for line in p.stdout:
        f = line.rstrip('\r\n').split(' ')
        if offset:
            if f[0] in ['nv', 'default']:
                continue
            f[0] = str(float(f[0]) + offset)
        fh.write(' '.join(f) + '\n')
    p.wait()
Exemple #7
0
def copy_colors(fh, map, offset):
    p = gscript.pipe_command("r.colors.out", map=map)
    for line in p.stdout:
        f = gscript.decode(line).rstrip("\r\n").split(" ")
        if offset:
            if f[0] in ["nv", "default"]:
                continue
            f[0] = str(float(f[0]) + offset)
        fh.write(gscript.encode(" ".join(f) + "\n"))
    p.wait()
Exemple #8
0
def copy_colors(fh, map, offset):
    p = grass.pipe_command('r.colors.out', map=map)
    for line in p.stdout:
        f = line.rstrip('\r\n').split(' ')
        if offset:
            if f[0] in ['nv', 'default']:
                continue
            f[0] = str(float(f[0]) + offset)
        fh.write(' '.join(f) + '\n')
    p.wait()
Exemple #9
0
def perform_stats(
    raster,
    percentile,
    fi,
    dbfdriver,
    colprefix,
    variables_dbf,
    variables,
    colnames,
    extstat,
):
    with open(sqltmp, "w") as f:
        # do the stats
        p = grass.pipe_command(
            "r.univar",
            flags="t" + extstat,
            map=raster,
            zones=rastertmp,
            percentile=percentile,
            sep=";",
        )

        first_line = 1

        f.write("{0}\n".format(grass.db_begin_transaction(fi["driver"])))
        for line in p.stdout:
            if first_line:
                first_line = 0
                continue

            vars = decode(line).rstrip("\r\n").split(";")

            f.write("UPDATE %s SET" % fi["table"])
            first_var = 1
            for colname in colnames:
                variable = colname.replace("%s_" % colprefix, "", 1)
                if dbfdriver:
                    variable = variables_dbf[variable]
                i = variables[variable]
                value = vars[i]
                # convert nan, +nan, -nan, inf, +inf, -inf, Infinity, +Infinity,
                # -Infinity to NULL
                if value.lower().endswith("nan") or "inf" in value.lower():
                    value = "NULL"
                if not first_var:
                    f.write(" , ")
                else:
                    first_var = 0
                f.write(" %s=%s" % (colname, value))

            f.write(" WHERE %s=%s;\n" % (fi["key"], vars[0]))
        f.write("{0}\n".format(grass.db_commit_transaction(fi["driver"])))
        p.wait()
Exemple #10
0
def main():
    options, flags = gs.parser()

    vector = options["input"]
    layer = 1
    raster = options["output"]
    method = options["method"]
    z = 3
    sep = "pipe"
    out_args = {}

    if not gs.find_file(vector, element="vector")["fullname"]:
        gs.fatal("Vector map <{0}> not found".format(vector))

    if options["column"]:
        z = 4
        out_args["column"] = options["column"]
        out_args["where"] = "{0} IS NOT NULL".format(options["column"])

        columns = gs.vector_columns(vector)

        if options["column"] not in columns:
            gs.fatal(_("Column <{0}> not found".format(options["column"])))
        if columns[options["column"]]["type"] not in ("INTEGER",
                                                      "DOUBLE PRECISION"):
            gs.fatal(_("Column <{0}> is not numeric".format(
                options["column"])))

    out_process = gs.pipe_command(
        "v.out.ascii",
        input=vector,
        layer=layer,
        format="point",
        separator=sep,
        flags="r",
        **out_args,
    )
    in_process = gs.start_command(
        "r.in.xyz",
        input="-",
        output=raster,
        method=method,
        z=z,
        separator=sep,
        stdin=out_process.stdout,
    )
    in_process.communicate()
    out_process.wait()

    return 0
Exemple #11
0
def perform_stats(raster, percentile, fi, dbfdriver, colprefix, variables_dbf,
                  variables, colnames, extstat):
    with open(sqltmp, 'w') as f:
        # do the stats
        p = grass.pipe_command('r.univar',
                               flags='t' + extstat,
                               map=raster,
                               zones=rastertmp,
                               percentile=percentile,
                               sep=';')

        first_line = 1

        f.write("{0}\n".format(grass.db_begin_transaction(fi['driver'])))
        for line in p.stdout:
            if first_line:
                first_line = 0
                continue

            vars = decode(line).rstrip('\r\n').split(';')

            f.write("UPDATE %s SET" % fi['table'])
            first_var = 1
            for colname in colnames:
                variable = colname.replace("%s_" % colprefix, '', 1)
                if dbfdriver:
                    variable = variables_dbf[variable]
                i = variables[variable]
                value = vars[i]
                # convert nan, +nan, -nan, inf, +inf, -inf, Infinity, +Infinity,
                # -Infinity to NULL
                if value.lower().endswith('nan') or 'inf' in value.lower():
                    value = 'NULL'
                if not first_var:
                    f.write(" , ")
                else:
                    first_var = 0
                f.write(" %s=%s" % (colname, value))

            f.write(" WHERE %s=%s;\n" % (fi['key'], vars[0]))
        f.write("{0}\n".format(grass.db_commit_transaction(fi['driver'])))
        p.wait()
def get_maps(stvds):
    """
    Get vector maps registered in an input stvds
    :param stvds: Spatio temporal vector dataset intended to convert
    :return maps: dictionary in format {vector map: [layers of vector map]}
    """

    listOutput = pipe_command('t.vect.list', input=stvds)
    listOutput = listOutput.communicate()[0]
    maps = dict()
    first = True

    for oneMap in listOutput.splitlines():
        if first is False:
            if oneMap.split('|')[0] in maps.keys():
                maps[oneMap.split('|')[0]].append(oneMap.split('|')[1])
            else:
                maps.update({oneMap.split('|')[0]: [oneMap.split('|')[1]]})
        else:
            first = False

    return maps
def main():
    options, flags = gs.parser()

    vector = options['input']
    layer = 1
    raster = options['output']
    method = options['method']
    z = 3
    sep = 'pipe'
    out_args = {}

    if not gs.find_file(vector, element='vector')['fullname']:
        gs.fatal('Vector map <{0}> not found'.format(vector))

    if options['column']:
        z = 4
        out_args['column'] = options['column']
        out_args['where'] = '{0} IS NOT NULL'.format(options['column'])

        columns = gs.vector_columns(vector)

        if options['column'] not in columns:
            gs.fatal(_('Column <{0}> not found'.format(options['column'])))
        if columns[options['column']]['type'] not in ('INTEGER', 'DOUBLE PRECISION'):
            gs.fatal(_('Column <{0}> is not numeric'.format(options['column'])))


    out_process = gs.pipe_command(
        'v.out.ascii', input=vector, layer=layer, format='point',
        separator=sep, flags='r', **out_args)
    in_process = gs.start_command(
        'r.in.xyz', input='-', output=raster, method=method, z=z,
        separator=sep, stdin=out_process.stdout)
    in_process.communicate()
    out_process.wait()

    return 0
def output_centerline(river, stations, elev, outfile):
	""" 
	Output the river network, including centerline for each reach
	and coordinates for all stations along each reach
	"""

	# Begin with the list of reach cats
	rc=grass.read_command('v.category', input=river, type="line", option="print")
	reach_cats=rc.strip().split("\n")
	
	outfile.write("BEGIN STREAM NETWORK:\n")
	# Now get points from the river vector, one pair for each reach
	for i in range(len(reach_cats)):
		where_cond="cat="+str(reach_cats[i])
		riv=grass.read_command('v.db.select',map=river, separator=" ", 
				columns="cat,start_x,start_y,end_x,end_y", where=where_cond, flags="c")
		riv_pts=riv.strip().split(" ")
		pi,x1,y1,x2,y2 = riv_pts[0],riv_pts[1],riv_pts[2],riv_pts[3],riv_pts[4]
		# Give the start point a point id of "cat"1, and the endpoint an id of "cat"2
		pi1 = pi+"1"
		pi2 = pi+"2"
		# Get elevation of each endpoint from the elev raster
		coords=x1+","+y1
		e = grass.read_command('r.what', map=elev, coordinates=coords, separator=",")
		start_elev=e.split(",")[3].rstrip()
		coords=x2+","+y2
		e = grass.read_command('r.what', map=elev, coordinates=coords, separator=",")
		end_elev=e.split(",")[3].rstrip()
		outfile.write(" ENDPOINT: "+x1+","+y1+","+start_elev+","+pi1+"\n")
		outfile.write(" ENDPOINT: "+x2+","+y2+","+end_elev+","+pi2+"\n")

	# Loop thru the reach_cats again, and output a REACH: section for each reach, 
	# with all points for that reach
	for i in range(len(reach_cats)):
		outfile.write(" REACH:\n")
		outfile.write("   STREAM ID: %s\n" % river)
		reach_id=str(reach_cats[i])
		outfile.write("   REACH ID: %s\n" % reach_id)
		# Get the FROM POINT and TO POINT ids just like above
		where_cond="cat="+str(reach_cats[i])
		riv=grass.read_command('v.db.select',map=river, separator=" ", 
				columns="cat,start_x,end_x,start_y,end_y", where=where_cond, flags="c")
		r_pts=riv.strip().split(" ")
		pi,x1,y1,x2,y2 = r_pts[0],r_pts[1],r_pts[2],r_pts[3],r_pts[4]
		# Give the start point a point id of "cat"1, and the endpoint a n id of "cat"2
		pi1 = pi+"1"
		pi2 = pi+"2"
		outfile.write("   FROM POINT: %s\n" % pi1)
		outfile.write("   TO POINT: %s\n" % pi2)

		# Now the actual points along centerline
		outfile.write("   CENTERLINE:\n")
		# loop thru the stations point vector to get each station's x,y and id
		reach_cond="reach_id="+reach_cats[i]
		p=grass.pipe_command('v.db.select', map=stations, where=reach_cond, quiet=True, flags="c")
		st_list=[]
		for line in p.stdout:
			st=line.strip().split('|')
			s,x,y = st[0], st[1], st[2]
			st_list.append([s,x,y])

		p.stdout.close()
		p.wait()
		# Now write out all station points to the CENTERLINE section
		# Go thru the st_list in reverse order so that the centerline is from upstream to downstream
		for i in range(len(st_list)-1, -1, -1):
			outfile.write("	"+st_list[i][1]+","+st_list[i][2]+",NULL,"+st_list[i][0]+"\n")

		outfile.write(" END:\n")

	# Close STREAM NETWORK section
	outfile.write("END STREAM NETWORK:\n\n")
Exemple #15
0
def reclass(inf, outf, lim, clump, diag, les):
    infile = inf
    outfile = outf
    lesser = les
    limit = lim
    clumped = clump
    diagonal = diag

    s = grass.read_command("g.region", flags='p')
    s = decode(s)
    kv = grass.parse_key_val(s, sep=':')
    s = kv['projection'].strip().split()
    if s == '0':
        grass.fatal(_("xy-locations are not supported"))
        grass.fatal(_("Need projected data with grids in meters"))

    if not grass.find_file(infile)['name']:
        grass.fatal(_("Raster map <%s> not found") % infile)

    if clumped and diagonal:
        grass.fatal(_("flags c and d are mutually exclusive"))

    if clumped:
        clumpfile = infile
    else:
        clumpfile = "%s.clump.%s" % (infile.split('@')[0], outfile)
        TMPRAST.append(clumpfile)

        if not grass.overwrite():
            if grass.find_file(clumpfile)['name']:
                grass.fatal(_("Temporary raster map <%s> exists") % clumpfile)
        if diagonal:
            grass.message(
                _("Generating a clumped raster file including "
                  "diagonal neighbors..."))
            grass.run_command('r.clump',
                              flags='d',
                              input=infile,
                              output=clumpfile)
        else:
            grass.message(_("Generating a clumped raster file ..."))
            grass.run_command('r.clump', input=infile, output=clumpfile)

    if lesser:
        grass.message(
            _("Generating a reclass map with area size less than "
              "or equal to %f hectares...") % limit)
    else:
        grass.message(
            _("Generating a reclass map with area size greater "
              "than or equal to %f hectares...") % limit)

    recfile = outfile + '.recl'
    TMPRAST.append(recfile)

    sflags = 'aln'
    if grass.raster_info(infile)['datatype'] in ('FCELL', 'DCELL'):
        sflags += 'i'
    p1 = grass.pipe_command('r.stats',
                            flags=sflags,
                            input=(clumpfile, infile),
                            sep=';')
    p2 = grass.feed_command('r.reclass',
                            input=clumpfile,
                            output=recfile,
                            rules='-')
    rules = ''
    for line in p1.stdout:
        f = decode(line).rstrip(os.linesep).split(';')
        if len(f) < 5:
            continue
        hectares = float(f[4]) * 0.0001
        if lesser:
            test = hectares <= limit
        else:
            test = hectares >= limit
        if test:
            rules += "%s = %s %s\n" % (f[0], f[2], f[3])
    if rules:
        p2.stdin.write(encode(rules))
    p1.wait()
    p2.stdin.close()
    p2.wait()
    if p2.returncode != 0:
        if lesser:
            grass.fatal(
                _("No areas of size less than or equal to %f "
                  "hectares found.") % limit)
        else:
            grass.fatal(
                _("No areas of size greater than or equal to %f "
                  "hectares found.") % limit)
    grass.mapcalc("$outfile = $recfile", outfile=outfile, recfile=recfile)
Exemple #16
0
def main():
    global tmp, tmp_proj, tmp_gpx, tmp_extr, tmp_vogb

    format = options['format']
    input = options['input']
    layer = options['layer']
    output = options['output']
    type = options['type']
    where = options['where']
    wpt = flags['w']
    rte = flags['r']
    trk = flags['t']

    nflags = len(filter(None, [wpt, rte, trk]))
    if nflags > 1:
	grass.fatal(_("One feature at a time please."))
    if nflags < 1:
	grass.fatal(_("No features requested for export."))

    # set some reasonable defaults
    if not type:
	if wpt:
	    type = 'point'
	else:
	    type = 'line'

    #### check for gpsbabel
    ### FIXME: may need --help or similar?
    if not grass.find_program("gpsbabel"):
	grass.fatal(_("The gpsbabel program was not found, please install it first.\n") +
		    "http://gpsbabel.sourceforge.net")

    #### check for cs2cs
    if not grass.find_program("cs2cs"):
	grass.fatal(_("The cs2cs program was not found, please install it first.\n") +
		    "http://proj.osgeo.org")

    # check if we will overwrite data
    if os.path.exists(output) and not grass.overwrite():
	grass.fatal(_("Output file already exists."))

    #### set temporary files
    tmp = grass.tempfile()

    # SQL extract if needed
    if where:
	grass.verbose("Extracting data ...")
	tmp_extr = "tmp_vogb_extr_%d" % os.getpid()
	ret = grass.run_command('v.extract', input = "$GIS_OPT_INPUT",
				output = tmp_extr, type = type, layer = layer,
				where = where, quiet = True)
	if ret != 0:
	    grass.fatal(_("Error executing SQL query"))

	kv = grass.vector_info_topo(tmp_extr)
	if kv['primitives'] == 0:
	    grass.fatal(_("SQL query returned an empty map (no %s features?)") % type)

	inmap = tmp_extr
    else:
	#   g.copy "$GIS_OPT_INPUT,tmp_vogb_extr_$$"   # to get a copy of DB into local mapset
	#   INMAP="tmp_vogb_extr_$$"
	inmap = input

    #### set up projection info
    # TODO: check if we are already in ll/WGS84.  If so skip m.proj step.

    # TODO: multi layer will probably fail badly due to sed 's/^ 1   /'
    #   output as old GRASS 4 vector ascii and fight with dig_ascii/?
    #   Change to s/^ \([0-9]   .*\)    /# \1/' ??? mmph.

    # reproject to lat/lon WGS84
    grass.verbose("Reprojecting data ...")

    re1 = re.compile(r'^\([PLBCFKA]\)')
    re2 = re.compile(r'^ 1     ')

    re3 = re.compile(r'\t\([-\.0-9]*\) .*')
    re4 = re.compile(r'^\([-\.0-9]\)')
    re5 = re.compile(r'^#')

    tmp_proj = tmp + ".proj"
    tf = open(tmp_proj, 'w')
    p1 = grass.pipe_command('v.out.ascii', input = inmap, format = 'standard')
    p2 = grass.feed_command('m.proj', input = '-', flags = 'od', quiet = True, stdout = tf)
    tf.close()

    lineno = 0
    for line in p1.stdout:
	lineno += 1
	if lineno < 11:
	    continue
	line = re1.sub(r'#\1', line)
	line = re2.sub(r'# 1  ', line)
	p2.stdin.write(line)

    p2.stdin.close()
    p1.wait()
    p2.wait()

    if p1.returncode != 0 or p2.returncode != 0:
	grass.fatal(_("Error reprojecting data"))

    tmp_vogb = "tmp_vogb_epsg4326_%d" % os.getpid()
    p3 = grass.feed_command('v.in.ascii', out = tmp_vogb, format = 'standard', flags = 'n', quiet = True)
    tf = open(tmp_proj, 'r')

    for line in tf:
	line = re3.sub(r' \1', line)
	line = re4.sub(r' \1', line)
	line = re5.sub('', line)
	p3.stdin.write(line)

    p3.stdin.close()
    tf.close()
    p3.wait()

    if p3.returncode != 0:
	grass.fatal(_("Error reprojecting data"))

    # don't v.db.connect directly as source table will be removed with
    # temporary map in that case. So we make a temp copy of it to work with.
    kv = vector_db(inmap)
    if layer in kv:
	db_params = kv[layer]

	db_table = db_params['table']
	db_key = db_params['key']
	db_database = db_params['database']
	db_driver = db_params['driver']

	ret = grass.run_command('db.copy',
				from_driver = db_driver,
				from_database = db_database,
				from_table = db_table,
				to_table = tmp_vogb)
	if ret != 0:
	    grass.fatal(_("Error copying temporary DB"))

	ret = grass.run_command('v.db.connect', map = tmp_vogb, table = tmp_vogb, quiet = True)
	if ret != 0:
	    grass.fatal(_("Error reconnecting temporary DB"))

    # export as GPX using v.out.ogr
    if trk:
	linetype = "FORCE_GPX_TRACK=YES"
    elif rte:
	linetype = "FORCE_GPX_TRACK=YES"
    else:
	linetype = None

    # BUG: cat is being reported as evelation and attribute output is skipped.
    #   (v.out.ogr DB reading or ->OGR GPX driver bug<-
    #     resolved: see new Create opts at http://www.gdal.org/ogr/drv_gpx.html)
    #   v.out.ogr -> shapefile -> GPX works, but we try to avoid that as it's
    #     lossy. Also that would allow ogr2ogr -a_srs $IN_PROJ -t_srs EPSG:4326
    #     so skip m.proj pains.. if that is done ogr2ogr -s_srs MUST HAVE +wktext
    #     with PROJ.4 terms or else the +nadgrids will be ignored! best to feed
    #     it  IN_PROJ="`g.proj -jf` +wktext"  in that case.

    grass.verbose("Exporting data ...")

    tmp_gpx = tmp + ".gpx"
    ret = grass.run_command('v.out.ogr', input = tmp_vogb, dsn = tmp_gpx,
			    type = type, format = 'GPX', lco = linetype,
			    dsco = "GPX_USE_EXTENSIONS=YES", quiet = True)
    if ret != 0:
	grass.fatal(_("Error exporting data"))

    if format == 'gpx':
	# short circuit, we have what we came for.
	grass.try_remove(output)
	os.rename(tmp_gpx, output)
	grass.verbose("Fast exit.")
	sys.exit()

    # run gpsbabel
    if wpt:
	gtype = '-w'
    elif trk:
	gtype = '-t'
    elif rte:
	gtype = '-r'
    else:
	gtype = ''

    grass.verbose("Running GPSBabel ...")

    ret = grass.call(['gpsbabel',
		      gtype,
		      '-i', 'gpx',
		      '-f', tmp + '.gpx',
		      '-o', format,
		      '-F', output])

    if ret != 0:
	grass.fatal(_("Error running GPSBabel"))

    grass.verbose("Done.")
Exemple #17
0
def main():
    check_progs()
    
    inmap = options['input']
    output = options['ldm']
    width = options['width']
    color = options['color']
    graph = options['graph']
    ldm_type = options['type']

    mapset = grass.gisenv()['MAPSET']

    global tmp, nuldev, grass_version
    nuldev = None

    grass_version = grass.version()['version'][0]
    if grass_version != '7':
        grass.fatal(_("Sorry, this script works in GRASS 7.* only"))

    # setup temporary files
    tmp = grass.tempfile()
    
    # check for LatLong location
    if grass.locn_is_latlong() == True:
        grass.fatal("Module works only in locations with cartesian coordinate system")


    # check if input file exists
    if not grass.find_file(inmap, element = 'vector')['file']:
        grass.fatal(_("<%s> does not exist.") % inmap)
        
    # check for lines
    iflines = grass.vector_info_topo(inmap)['lines']
    if iflines == 0:
        grass.fatal(_("Map <%s> has no lines.") % inmap)
    

    # diplay options 
    if flags['x']:
        env = grass.gisenv()
        mon = env.get('MONITOR', None)
        if not mon:
            if not graph:
                grass.fatal(_("Please choose \"graph\" output file with LDM graphics or not use flag \"x\""))

    
    ####### DO IT #######
    # copy input vector map and drop table
    grass.run_command('g.copy', vect = (inmap, 'v_ldm_vect'), quiet = True, stderr = nuldev)
    db = grass.vector_db('v_ldm_vect')
    if db != {}:
        grass.run_command('v.db.droptable', map_ = 'v_ldm_vect', flags = 'f', quiet = True, stderr = nuldev)

    # compute mean center of lines with v.mc.py module
    center_coords = grass.read_command('v.mc.py', input_ = inmap, type_ = 'line',
                                quiet = True, stderr = nuldev).strip()
    mc_x = center_coords.split(' ')[0]
    mc_y = center_coords.split(' ')[1]

    center_coords = str(mc_x) + ',' + str(mc_y)

    ### 
    inmap = 'v_ldm_vect'

    # count lines
    count = grass.vector_info_topo(inmap)['lines']

    # add temp table with azimuths and lengths of lines
    in_cats = inmap + '_cats'    
    grass.run_command('v.category', input_ = inmap, option = 'add', 
                      output = in_cats, quiet = True, stderr = nuldev)
    grass.run_command('v.db.addtable', map_ = in_cats, table = 'tmp_tab', 
                      columns = 'sum_azim double, len double', quiet = True, stderr = nuldev)
    grass.run_command('v.db.connect', map_ = in_cats, table = 'tmp_tab', 
                      flags = 'o', quiet = True, stderr = nuldev)
    grass.run_command('v.to.db', map_ = in_cats, opt = 'azimuth', 
                      columns = 'sum_azim', units = 'radians', quiet = True, stderr = nuldev)
    grass.run_command('v.to.db', map_ = in_cats, opt = 'length',  
                      columns = 'len', units = 'meters', quiet = True, stderr = nuldev)    

    # find end azimuth
    p = grass.pipe_command('v.db.select', map_ = in_cats, columns = 'sum_azim', flags = 'c', quiet = True, stderr = nuldev)
    c = p.communicate()[0].strip().split('\n')

    sin = []
    cos = []
    
    for i in c:
        s1 = math.sin(float(i))
        c1 = math.cos(float(i))
        sin.append(s1)
        cos.append(c1)

    ca_sin = sum(map(float,sin))
    ca_cos = sum(map(float,cos))
    
    atan = math.atan2(ca_sin,ca_cos)
    end_azim = math.degrees(atan)

    # find compass angle    
    if end_azim < 0:
        a2 = -(end_azim)
    if end_azim > 0:
        a2 = end_azim
    if (ca_sin > 0) and (ca_cos > 0):
        comp_angle = a2
    if (ca_sin > 0) and (ca_cos < 0):
        comp_angle = a2
    if (ca_sin < 0) and (ca_cos > 0):
        comp_angle = 360 - a2
    if (ca_sin < 0) and (ca_cos < 0):
        comp_angle = 360 - a2

    # find LDM
    if end_azim < 0:
        a2 = -(end_azim)
    if end_azim > 0:
        a2 = end_azim
    if (ca_sin > 0) and (ca_cos > 0):
        ldm = 90 - a2
    if (ca_sin > 0) and (ca_cos < 0):
        ldm = 450 - a2
    if (ca_sin < 0) and (ca_cos > 0):
        ldm = 90 + a2
    if (ca_sin < 0) and (ca_cos < 0):
        ldm = 90 + a2

    # find circular variance
    sin_pow = math.pow(ca_sin,2) 
    cos_pow = math.pow(ca_cos,2) 

    circ_var = 1-(math.sqrt(sin_pow+cos_pow))/count

    # find start/end points of "mean" line
    end_azim_dms = decimal2dms(end_azim)

    # if end_azim < 0:
    #     end_azim_dms = '-' + (str(end_azim_dms))

    start_azim = 180 - end_azim
    start_azim_dms = decimal2dms(start_azim)
    
    p = grass.pipe_command('v.db.select', map_ = in_cats, columns = 'len',
                           flags = 'c', quiet = True, stderr = nuldev)
    c = p.communicate()[0].strip().split('\n')

    mean_length = sum(map(float,c))/len(c)
    half_length = float(mean_length)/2

    tmp1 = tmp + '.inf'
    inf1 = file(tmp1, 'w')
    print >> inf1, 'N ' + str(end_azim_dms) + ' E ' + str(half_length)
    inf1.close()
    
    end_coords = grass.read_command('m.cogo', input_ = tmp1, output = '-',
                                    coord = center_coords, quiet = True).strip()

    tmp2 = tmp + '.inf2'
    inf2 = file(tmp2, 'w')
    print >> inf2, 'N ' + str(start_azim_dms) + ' W ' + str(half_length)
    inf2.close()

    start_coords = grass.read_command('m.cogo', input_ = tmp2, output = '-',
                                      coord = center_coords, quiet = True).strip()

    # make "arrowhead" symbol
    if flags['x'] or graph:
        tmp3 = tmp + '.arrowhead_1'
        outf3 = file(tmp3, 'w')

        if ldm_type == 'direct':
            t1 = """VERSION 1.0
BOX -0.5 -0.5 0.5 0.5
POLYGON
  RING
  FCOLOR NONE
    LINE
      0 0
      0.3 -1
    END
  END
POLYGON
  RING
  FCOLOR NONE
    LINE
      0 0
      -0.3 -1
    END
  END
END
"""
            outf3.write(t1)
            outf3.close()
    
            gisdbase = grass.gisenv()['GISDBASE']
            location = grass.gisenv()['LOCATION_NAME']
            mapset = grass.gisenv()['MAPSET']
            symbols_dir = os.path.join(gisdbase, location, mapset, 'symbol', 'arrows')
            symbol = os.path.join(symbols_dir, 'arrowhead_1')
    
            if not os.path.exists(symbols_dir):
                try:
                    os.makedirs(symbols_dir)
                except OSError:
                    pass
        
            if not os.path.isfile(symbol):
                shutil.copyfile(tmp3, symbol)
        
    
        # write LDM graph file and optionally display line of LDM with an arrow
    tmp4 = tmp + '.ldm'
    outf4 = file(tmp4, 'w')
    
    arrow_size = int(width) * 1.4
    arrow_azim = 360 - float(end_azim)

    if ldm_type == 'direct':
        t2 = string.Template("""
move $start_coords
width $width
color $color
draw $end_coords

rotation $arrow_azim
width $width
symbol $symbol_s $arrow_size $end_coords $color
""")    
        s2 = t2.substitute(start_coords = start_coords, width = width, color = color,
                       end_coords = end_coords, arrow_azim = arrow_azim,
                       symbol_s = "arrows/arrowhead_1", arrow_size = arrow_size)
    else:
        t2 = string.Template("""
move $start_coords
width $width
color $color
draw $end_coords
""")    
        s2 = t2.substitute(start_coords = start_coords, width = width, color = color,
                       end_coords = end_coords)

    outf4.write(s2)
    outf4.close()

    if graph:
        shutil.copy(tmp4, graph)



    # save LDM line to vector if option "output" set  
    if output:
        tmp5 = tmp + '.line'
        outf5 = file(tmp5, 'w')

        print >> outf5, str(start_coords)
        print >> outf5, str(end_coords)

        outf5.close()

        grass.run_command('v.in.lines', input_ = tmp5, output = output,
                              separator = " ", overwrite = True, quiet = True)

        out_cats = output + '_cats'
        grass.run_command('v.category', input_ = output, option = 'add', 
                          output = out_cats, quiet = True, stderr = nuldev)
        grass.run_command('g.rename', vect = (out_cats,output), 
                          overwrite = True, quiet = True, stderr = nuldev)
        
        if circ_var:
            col = 'comp_angle double,dir_mean double,cir_var double,ave_x double,ave_y double,ave_len double'
        else:
            col = 'comp_angle double,dir_mean double,ave_x double,ave_y double,ave_len double'
                        
        grass.run_command('v.db.addtable', map_ = output, columns = col, quiet = True, stderr = nuldev)

        tmp6 = tmp + '.sql'
        outf6 = file(tmp6, 'w')
                
        t3 = string.Template("""
UPDATE $output SET comp_angle = $comp_angle;
UPDATE $output SET dir_mean = $ldm;
UPDATE $output SET ave_x = $mc_x;
UPDATE $output SET ave_y = $mc_y;
UPDATE $output SET ave_len = $mean_length;
""")
        s3 = t3.substitute(output = output, comp_angle = ("%0.3f" % comp_angle),
                           ldm = ("%0.3f" % ldm), mc_x = ("%0.3f" % float(mc_x)),
                           mc_y = ("%0.3f" % float(mc_y)), mean_length = ("%0.3f" % mean_length))
        outf6.write(s3)

        if circ_var:
            print >> outf6, "UPDATE %s SET cir_var = %0.3f;" % (output, circ_var)

        outf6.close()

        grass.run_command('db.execute', input_ = tmp6, quiet = True, stderr = nuldev)


    # print LDM parameters to stdout (with <-g> flag in shell style):
    print_out = ['Compass Angle', 'Directional Mean', 'Average Center', 'Average Length']
    if circ_var:
        print_out.append('Circular Variance')
        
    print_shell = ['compass_angle', 'directional_mean', 'average_center',
                   'average_length', 'circular_variance']
    if circ_var:
        print_shell.append('circular_variance')
        
    print_vars = ["%0.3f" % comp_angle, "%0.3f" % ldm,
                  "%0.3f" % float(mc_x) + ',' + "%0.3f" % float(mc_y),
                  "%0.3f" % mean_length]
    if circ_var:
        print_vars.append("%0.3f" % circ_var)


    if flags['g']:
        for i,j in zip(print_shell, print_vars):
            print "%s=%s" % (i, j)
    else:
        for i,j in zip(print_out, print_vars):
            print "%s: %s" % (i, j)


    # diplay LDM graphics
    if flags['x']:
        if mon:
            if graph:
                grass.run_command('d.graph', input_ = graph, flags = 'm', quiet = True, stderr = nuldev)
            else:
                grass.run_command('d.graph', input_ = tmp4, flags = 'm', quiet = True, stderr = nuldev)
        elif graph:
            grass.message(_("\n Use this command in wxGUI \"Command console\" or with <d.mon> or with \"command layer\" to display LDM graphics: \n d.graph -m input=%s \n\n" ) % graph)
Exemple #18
0
# Import the points from the vector location and set the region bounds
print "Importing points from vector location"
v.proj(input=vector_layer, location=vector_location, mapset="PERMANENT")
g.run_command("g.region", vect=vector_layer)

# Build the Heatmap
print "Building heatmap: %s" % raster_layer
v.kernel(input=vector_layer, output=raster_layer, radius=radius)

# Generate the layer statistics and extract the maximum value
# Since we're doing some sorting ourselves, we'll be using r.stats
# instead of r.report
print "Getting layer stats"
vals = []
output = g.pipe_command('r.stats', input=raster_layer)
for line in output.stdout:
    vals.append(float(line.rstrip('\r\n').split('-')[1]))

print "Layer maximum value: %s" % vals[-1]

# Recode the raster using these rules
# A better solution would be to read in a rules file, but I'm too lazy.
# If you want to do that, you'll need to specify a file location
#   and remove the write_command call.
# We're also going to be really snarky and recode to the maximum int value (255).
    #That's mostly because I don't know how to programmatically
    #rescale a float to an int
print "Recoding raster layer"
rules = "0.0:" + str(vals[-1]) + ":0:255"
#r.recode(input=raster_layer, rules=rules, output=recoded_raster_layer)
Exemple #19
0
def main():
    global far_edge_value
    global d_max

    options, flags = gscript.parser()
    high = options["high"]
    low = options["low"]
    output = options["output"]
    far_edge = float(options["far_edge"])
    inter_points = int(options["inter_points"])
    use_average_differences = flags["a"]

    if high is None or high == "":
        gscript.error(_("[r.mblend] ERROR: high is a mandatory parameter."))
        exit()

    if low is None or low == "":
        gscript.error(_("[r.mblend] ERROR: low is a mandatory parameter."))
        exit()

    if output is None or output == "":
        gscript.error(_("[r.mblend] ERROR: output is a mandatory parameter."))
        exit()

    if far_edge < 0 or far_edge > 100:
        gscript.error(
            _("[r.mblend] ERROR: far_edge must be a percentage",
              " between 0 and 100."))
        exit()

    if inter_points < 0:
        gscript.error(
            _("[r.mblend] ERROR: inter_points must be a positive",
              " integer."))
        exit()

    # Set the region to the two input rasters
    gscript.run_command("g.region", raster=high + "," + low)
    # Determine cell side
    region = gscript.region()
    if region["nsres"] > region["ewres"]:
        cell_side = region["nsres"]
    else:
        cell_side = region["ewres"]

    compute_d_max(region)

    # Make cell size compatible
    low_res_inter = getTemporaryIdentifier()
    gscript.message(
        _("[r.mblend] Resampling low resolution raster to higher" +
          " resolution"))
    gscript.run_command("r.resamp.interp",
                        input=low,
                        output=low_res_inter,
                        method="nearest")

    # Obtain extent to interpolate
    low_extent_rast = getTemporaryIdentifier()
    high_extent_rast = getTemporaryIdentifier()
    low_extent = getTemporaryIdentifier()
    high_extent = getTemporaryIdentifier()
    interpol_area = getTemporaryIdentifier()
    gscript.message(_("[r.mblend] Multiplying low resolution by zero"))
    gscript.mapcalc(low_extent_rast + " = " + low + " * 0")
    gscript.message(_("[r.mblend] Multiplying high resolution by zero"))
    gscript.mapcalc(high_extent_rast + " = " + high + " * 0")
    gscript.message(_("[r.mblend] Computing extent of low resolution"))
    gscript.run_command("r.to.vect",
                        input=low_extent_rast,
                        output=low_extent,
                        type="area")
    gscript.message(_("[r.mblend] Computing extent of high resolution"))
    gscript.run_command("r.to.vect",
                        input=high_extent_rast,
                        output=high_extent,
                        type="area")
    gscript.message(_("[r.mblend] Computing area to interpolate"))
    gscript.run_command(
        "v.overlay",
        ainput=low_extent,
        binput=high_extent,
        output=interpol_area,
        operator="not",
    )

    # Compute difference between the two rasters and vectorise to points
    interpol_area_buff = getTemporaryIdentifier()
    diff = getTemporaryIdentifier()
    diff_points_edge = getTemporaryIdentifier()
    gscript.mapcalc(diff + " = " + high + " - " + low_res_inter)
    gscript.message(_("[r.mblend] Computing buffer around interpolation area"))
    gscript.run_command(
        "v.buffer",
        input=interpol_area,
        output=interpol_area_buff,
        type="area",
        distance=cell_side,
    )
    gscript.message(
        _("[r.mblend] Vectorising differences between input" + " rasters"))
    gscript.run_command("r.mask", vector=interpol_area_buff)
    gscript.run_command("r.to.vect",
                        input=diff,
                        output=diff_points_edge,
                        type="point")
    gscript.run_command("r.mask", flags="r")

    # Compute average of the differences if flag -a was passed
    if use_average_differences:
        p = gscript.pipe_command("r.univar", map=diff)
        result = {}
        for line in p.stdout:
            vector = line.split(": ")
            if vector[0] == "mean":
                print("Found it: " + vector[1])
                far_edge_value = vector[1]
        p.wait()

    # Get points in low resolution farther away from high resolution raster
    dist_high = getTemporaryIdentifier()
    weights = getTemporaryIdentifier()
    interpol_area_points = getTemporaryIdentifier()
    pre_interpol_area_points = getTemporaryIdentifier()
    weight_points = getTemporaryIdentifier()
    interpol_area_in_buff = getTemporaryIdentifier()
    weight_points_all_edges = getTemporaryIdentifier()
    weight_points_edge = getTemporaryIdentifier()
    # 1. Distance to High resolution raster
    gscript.message(
        _("[r.mblend] Computing distance to high resolution" + " raster"))
    gscript.run_command("r.grow.distance", input=high, distance=dist_high)
    # 2. Rescale to the interval [0,10000]: these are the weights
    gscript.message(_("[r.mblend] Rescaling distance to [0,10000] interval"))
    gscript.run_command("r.rescale",
                        input=dist_high,
                        output=weights,
                        to="0," + str(WEIGHT_MAX))
    # 3. Extract points from interpolation area border
    gscript.message(
        _("[r.mblend] Extract points from interpolation area " + "boundary"))
    gscript.run_command(
        "v.to.points",
        input=interpol_area,
        output=pre_interpol_area_points,
        type="boundary",
        dmax=d_max,
        layer="-1",
    )
    gscript.message(_("[r.mblend] Copying features to layer 1"))
    gscript.run_command(
        "v.category",
        input=pre_interpol_area_points,
        output=interpol_area_points,
        option="chlayer",
        layer="2,1",
    )
    gscript.message(_("[r.mblend] Linking attribute table to layer 1"))
    gscript.run_command(
        "v.db.connect",
        map=interpol_area_points,
        table=interpol_area_points,
        layer="1",
        flags="o",
    )
    # 4. Query distances to interpolation area points
    gscript.message(_("[r.mblend] Querying distances raster"))
    gscript.run_command("v.what.rast",
                        map=interpol_area_points,
                        raster=weights,
                        column=COL_VALUE)
    # 5. Select those with higher weights
    cut_off = str(far_edge / 100 * WEIGHT_MAX)
    gscript.message(
        _("[r.mblend] Selecting far edge points (using cut-off" +
          " percentage)"))
    gscript.run_command(
        "v.extract",
        input=interpol_area_points,
        output=weight_points_edge,
        where=COL_VALUE + ">" + cut_off,
    )

    # Merge the two point edges and set low res edge to zero
    points_edges = getTemporaryIdentifier()
    gscript.message(_("[r.mblend] Dropping extra column from far edge"))
    gscript.run_command("v.db.dropcolumn",
                        map=weight_points_edge,
                        layer="1",
                        columns="along")
    gscript.message(_("[r.mblend] Setting far edge weights to zero"))
    gscript.run_command("v.db.update",
                        map=weight_points_edge,
                        column=COL_VALUE,
                        value=far_edge_value)
    gscript.message(_("[r.mblend] Patching the two edges"))
    gscript.run_command(
        "v.patch",
        input=diff_points_edge + "," + weight_points_edge,
        output=points_edges,
        flags="e",
    )

    # Interpolate smoothing raster
    smoothing = getTemporaryIdentifier()
    interpol_area_rst = getTemporaryIdentifier()
    # Consign region to interpolation area
    gscript.run_command("g.region", vector=interpol_area_buff)
    gscript.message(
        _("[r.mblend] Interpolating smoothing surface. This" +
          " might take a while..."))
    gscript.run_command(
        "v.surf.idw",
        input=points_edges,
        column=COL_VALUE,
        output=smoothing,
        power=2,
        npoints=inter_points,
    )
    # Reset region to full extent
    gscript.run_command("g.region", raster=high + "," + low)

    # Apply stitching
    smooth_low_res = getTemporaryIdentifier()
    # Sum to low res
    gscript.message(_("[r.mblend] Applying smoothing surface"))
    gscript.mapcalc(smooth_low_res + " = " + low_res_inter + " + " + smoothing)
    # Add both rasters
    try:
        gscript.message(_("[r.mblend] Joining result into a single raster"))
        gscript.run_command("r.patch",
                            input=high + "," + smooth_low_res,
                            output=output)
    except Exception as ex:
        gscript.error(_("[r.mblend] ERROR: Failed to create smoothed raster."))
        exit()

    gscript.message(_("[r.mblend] SUCCESS: smoothed raster created."))
fn_out = prefix + '_' + year + '_' + suffix + '.tif'

t = time.time()

#for f in glob.glob('*.tif'):
#    grass.run_command('r.in.gdal', input=f, output=f.replace('.tif',''))
    
t_import = time.time() - t

#for f in glob.glob('*.tif'):
#    grass.run_command('r.null', map=f.replace('.tif',''), setnull="249,250,251,252,253,254,255")
#    
t_nodata = time.time() - t - t_import

result = ''
p = grass.pipe_command('g.mlist', type = 'rast', quiet=True, pattern=year + '*')
for line in p.stdout:
    result = result + ',' + line.replace('\n','')

input_rast_list = result.strip(',')

grass.run_command('r.series', input=input_rast_list, output='dh1_' + year + ',dh2_' + year + ',ave_' + year + ',std_' + year, method='sum,minimum,average,stddev')
grass.mapcalc('dh3_' + year + ' = std_' + year + '/ave_' + year)
t_calc = time.time() - t - t_import - t_nodata

grass.run_command('i.group', group='rgb_group_' + year, input='dh1_' + year + ',dh2_' + year + ',dh3_' + year)
grass.run_command('r.out.gdal', input='rgb_group_' + year, output=fn_out, type='Float32', createopt='PROFILE=BASELINE,INTERLEAVE=PIXEL,TFW=YES')
shutil.move(fn_out,od + fn_out)
shutil.move(fn_out.replace('.tif','.tfw'),od + fn_out.replace('.tif','.tfw'))
shutil.move(fn_out + '.aux.xml',od + fn_out + '.aux.xml')
cmd = "gdal_edit -a_srs \"EPSG:4326\" " + od + fn_out
Exemple #21
0
def do_it_all(global_vars, target_pts_np):
    """Conduct weighted and parametrised partial viewshed and cummulate it with
    the previous partial viewsheds
    :param target_pts_np: Array of target points in global coordinate system
    :type target_pts_np: ndarray
    :return: 2D array of weighted parametrised cummulative viewshed
    :rtype: ndarray
    """
    # Set counter
    counter = 1

    # Get variables out of global_vars dictionary
    reg = global_vars["region"]
    exp_range = global_vars["range"]
    flagstring = global_vars["flagstring"]
    r_dsm = global_vars["r_dsm"]
    v_elevation = global_vars["observer_elevation"]
    refr_coeff = global_vars["refr_coeff"]
    memory = global_vars["memory"]
    parametrise_viewshed = global_vars["param_viewshed"]
    dsm_type = global_vars["dsm_type"]
    b_1 = global_vars["b_1"]
    cores = global_vars["cores"]
    tempname = global_vars["tempname"]

    # Create empty viewshed
    np_cum = np.empty((reg.rows, reg.cols), dtype=np.single)
    np_cum[:] = np.nan
    tmp_vs = "{}_{}".format(tempname, os.getpid())

    for target_pnt in target_pts_np:

        # Display a progress info message
        grass.percent(counter, len(target_pts_np), 1)
        grass.verbose("Processing point {i} ({p:.1%})".format(
            i=int(target_pnt[0]), p=counter / len(target_pts_np)))

        # Global coordinates and attributes of target point T
        t_glob = target_pnt[1:]

        # ======================================================================
        # 1. Set local computational region: +/- exp_range from target point
        # ======================================================================
        # compute position of target point within a pixel
        delta_n = math.ceil(
            (t_glob[1] - reg.south) / reg.nsres) * reg.nsres - (t_glob[1] -
                                                                reg.south)
        delta_s = (t_glob[1] - reg.south) - math.floor(
            (t_glob[1] - reg.south) / reg.nsres) * reg.nsres
        delta_e = math.ceil(
            (t_glob[0] - reg.west) / reg.ewres) * reg.ewres - (t_glob[0] -
                                                               reg.west)
        delta_w = (t_glob[0] - reg.west) - math.floor(
            (t_glob[0] - reg.west) / reg.ewres) * reg.ewres

        # ensure that local region doesn't exceed global region
        loc_reg_n = min(t_glob[1] + exp_range + delta_n, reg.north)
        loc_reg_s = max(t_glob[1] - exp_range - delta_s, reg.south)
        loc_reg_e = min(t_glob[0] + exp_range + delta_e, reg.east)
        loc_reg_w = max(t_glob[0] - exp_range - delta_w, reg.west)

        # pygrass sets region for pygrass tasks
        lreg = deepcopy(reg)
        lreg.set_bbox(Bbox(loc_reg_n, loc_reg_s, loc_reg_e, loc_reg_w))
        lreg.set_raster_region()

        # Create processing environment with region information
        c_env = os.environ.copy()
        c_env["GRASS_REGION"] = grass.region_env(n=loc_reg_n,
                                                 s=loc_reg_s,
                                                 e=loc_reg_e,
                                                 w=loc_reg_w)

        lreg_shape = [lreg.rows, lreg.cols]

        # ======================================================================
        # 2. Calculate binary viewshed and convert to numpy
        # ======================================================================
        vs = grass.pipe_command(
            "r.viewshed",
            flags="b" + flagstring,
            input=r_dsm,
            output=tmp_vs,
            coordinates="{},{}".format(t_glob[0], t_glob[1]),
            observer_elevation=0.0,
            target_elevation=v_elevation,
            max_distance=exp_range,
            refraction_coeff=refr_coeff,
            memory=int(round(memory / cores)),
            quiet=True,
            overwrite=True,
            env=c_env,
        )
        vs.communicate()
        # Workaround for https://github.com/OSGeo/grass/issues/1436
        clean_temp(vs.pid)

        # Read viewshed into numpy with single precision and replace NoData
        np_viewshed = raster2numpy(tmp_vs).astype(np.single)
        np_viewshed[np_viewshed == -2147483648] = np.nan

        # ======================================================================
        # 3. Prepare local coordinates and attributes of target point T
        # ======================================================================
        # Calculate how much of rows/cols of local region lies
        # outside global region
        o_1 = [
            max(t_glob[1] + exp_range + reg.nsres / 2 - reg.north, 0),
            max(reg.west - (t_glob[0] - exp_range - reg.ewres / 2), 0),
        ]

        t_loc = np.append(
            np.array([
                exp_range / reg.nsres + 0.5 - o_1[0] / reg.nsres,
                exp_range / reg.ewres + 0.5 - o_1[1] / reg.ewres,
            ]),
            t_glob[2:],
        )

        # ======================================================================
        # 4. Parametrise viewshed
        # ======================================================================
        np_viewshed = parametrise_viewshed(
            lreg_shape,
            t_loc,
            np_viewshed,
            reg,
            exp_range,
            r_dsm,
            dsm_type,
            v_elevation,
            b_1,
        ).astype(np.single)

        # ======================================================================
        # 5. Cummulate viewsheds
        # ======================================================================
        # Determine position of local parametrised viewshed within
        # global cummulative viewshed
        o_2 = [
            int(round((reg.north - loc_reg_n) / reg.nsres)),  # NS (rows)
            int(round((loc_reg_w - reg.west) / reg.ewres)),  # EW (cols)
        ]

        # Add local parametrised viewshed to global cummulative viewshed
        # replace nans with 0 in processed regions, keep nan where both are nan
        all_nan = np.all(
            np.isnan([
                np_cum[o_2[0]:o_2[0] + lreg_shape[0],
                       o_2[1]:o_2[1] + lreg_shape[1]],
                np_viewshed,
            ]),
            axis=0,
        )

        np_cum[o_2[0]:o_2[0] + lreg_shape[0],
               o_2[1]:o_2[1] + lreg_shape[1]] = np.nansum(
                   [
                       np_cum[o_2[0]:o_2[0] + lreg_shape[0],
                              o_2[1]:o_2[1] + lreg_shape[1]],
                       np_viewshed,
                   ],
                   axis=0,
               )

        np_cum[o_2[0]:o_2[0] + lreg_shape[0],
               o_2[1]:o_2[1] + lreg_shape[1]][all_nan] = np.nan

        counter += 1

    return np_cum
Exemple #22
0
 def __unicode__(self):
     return grass.pipe_command("g.region", flags="pu").communicate()[0]
Exemple #23
0
def main():
    global tmp, sqltmp, tmpname, nuldev, vector, rastertmp
    rastertmp = False
    # setup temporary files
    tmp = grass.tempfile()
    sqltmp = tmp + ".sql"
    # we need a random name
    tmpname = grass.basename(tmp)

    nuldev = open(os.devnull, 'w')

    rasters = options['raster'].split(',')
    colprefixes = options['column_prefix'].split(',')
    vector = options['map']
    layer = options['layer']
    percentile = options['percentile']
    basecols = options['method'].split(',')

    ### setup enviro vars ###
    env = grass.gisenv()
    mapset = env['MAPSET']

    vs = vector.split('@')
    if len(vs) > 1:
        vect_mapset = vs[1]
    else:
        vect_mapset = mapset

    # does map exist in CURRENT mapset?
    if vect_mapset != mapset or not grass.find_file(vector, 'vector',
                                                    mapset)['file']:
        grass.fatal(_("Vector map <%s> not found in current mapset") % vector)

    # check if DBF driver used, in this case cut to 10 chars col names:
    try:
        fi = grass.vector_db(map=vector)[int(layer)]
    except KeyError:
        grass.fatal(
            _('There is no table connected to this map. Run v.db.connect or v.db.addtable first.'
              ))
    # we need this for non-DBF driver:
    dbfdriver = fi['driver'] == 'dbf'

    # colprefix for every raster map?
    if len(colprefixes) != len(rasters):
        grass.fatal(
            _("Number of raster maps ({0}) different from \
                      number of column prefixes ({1})".format(
                len(rasters), len(colprefixes))))

    vector = vs[0]

    rastertmp = "%s_%s" % (vector, tmpname)

    for raster in rasters:
        # check the input raster map
        if not grass.find_file(raster, 'cell')['file']:
            grass.fatal(_("Raster map <%s> not found") % raster)

    # save current settings:
    grass.use_temp_region()

    # Temporarily aligning region resolution to $RASTER resolution
    # keep boundary settings
    grass.run_command('g.region', align=rasters[0])

    # prepare base raster for zonal statistics
    try:
        nlines = grass.vector_info_topo(vector)['lines']
        # Create densified lines rather than thin lines
        if flags['d'] and nlines > 0:
            grass.run_command('v.to.rast',
                              input=vector,
                              layer=layer,
                              output=rastertmp,
                              use='cat',
                              flags='d',
                              quiet=True)
        else:
            grass.run_command('v.to.rast',
                              input=vector,
                              layer=layer,
                              output=rastertmp,
                              use='cat',
                              quiet=True)
    except CalledModuleError:
        grass.fatal(_("An error occurred while converting vector to raster"))

    # dump cats to file to avoid "too many argument" problem:
    p = grass.pipe_command('r.category', map=rastertmp, sep=';', quiet=True)
    cats = []

    for line in p.stdout:
        line = decode(line)
        cats.append(line.rstrip('\r\n').split(';')[0])
    p.wait()

    number = len(cats)
    if number < 1:
        grass.fatal(_("No categories found in raster map"))

    # Check if all categories got converted
    # Report categories from vector map
    vect_cats = grass.read_command('v.category',
                                   input=vector,
                                   option='report',
                                   flags='g').rstrip('\n').split('\n')

    # get number of all categories in selected layer
    for vcl in vect_cats:
        if vcl.split(' ')[0] == layer and vcl.split(' ')[1] == 'all':
            vect_cats_n = int(vcl.split(' ')[2])

    if vect_cats_n != number:
        grass.warning(
            _("Not all vector categories converted to raster. \
                         Converted {0} of {1}.".format(number, vect_cats_n)))

    # check if DBF driver used, in this case cut to 10 chars col names:
    try:
        fi = grass.vector_db(map=vector)[int(layer)]
    except KeyError:
        grass.fatal(
            _('There is no table connected to this map. Run v.db.connect or v.db.addtable first.'
              ))
    # we need this for non-DBF driver:
    dbfdriver = fi['driver'] == 'dbf'

    # Find out which table is linked to the vector map on the given layer
    if not fi['table']:
        grass.fatal(
            _('There is no table connected to this map. Run v.db.connect or v.db.addtable first.'
              ))

    # replaced by user choiche
    #basecols = ['n', 'min', 'max', 'range', 'mean', 'stddev', 'variance', 'cf_var', 'sum']

    for i in xrange(len(rasters)):
        raster = rasters[i]
        colprefix = colprefixes[i]
        # we need at least three chars to distinguish [mea]n from [med]ian
        # so colprefix can't be longer than 6 chars with DBF driver
        if dbfdriver:
            colprefix = colprefix[:6]
            variables_dbf = {}

        # by default perccol variable is used only for "variables" variable
        perccol = "percentile"
        perc = None
        for b in basecols:
            if b.startswith('p'):
                perc = b
        if perc:
            # namespace is limited in DBF but the % value is important
            if dbfdriver:
                perccol = "per" + percentile
            else:
                perccol = "percentile_" + percentile
            percindex = basecols.index(perc)
            basecols[percindex] = perccol

        # dictionary with name of methods and position in "r.univar -gt"  output
        variables = {
            'number': 2,
            'null_cells': 2,
            'minimum': 4,
            'maximum': 5,
            'range': 6,
            'average': 7,
            'stddev': 9,
            'variance': 10,
            'coeff_var': 11,
            'sum': 12,
            'first_quartile': 14,
            'median': 15,
            'third_quartile': 16,
            perccol: 17
        }
        # this list is used to set the 'e' flag for r.univar
        extracols = ['first_quartile', 'median', 'third_quartile', perccol]
        addcols = []
        colnames = []
        extstat = ""
        for i in basecols:
            # this check the complete name of out input that should be truncated
            for k in variables.keys():
                if i in k:
                    i = k
                    break
            if i in extracols:
                extstat = 'e'
            # check if column already present
            currcolumn = ("%s_%s" % (colprefix, i))
            if dbfdriver:
                currcolumn = currcolumn[:10]
                variables_dbf[currcolumn.replace("%s_" % colprefix, '')] = i

            colnames.append(currcolumn)
            if currcolumn in grass.vector_columns(vector, layer).keys():
                if not flags['c']:
                    grass.fatal(
                        (_("Cannot create column <%s> (already present). ") %
                         currcolumn) +
                        _("Use -c flag to update values in this column."))
            else:
                if i == "n":
                    coltype = "INTEGER"
                else:
                    coltype = "DOUBLE PRECISION"
                addcols.append(currcolumn + ' ' + coltype)

        if addcols:
            grass.verbose(_("Adding columns '%s'") % addcols)
            try:
                grass.run_command('v.db.addcolumn',
                                  map=vector,
                                  columns=addcols,
                                  layer=layer)
            except CalledModuleError:
                grass.fatal(_("Adding columns failed. Exiting."))

        # calculate statistics:
        grass.message(_("Processing input data (%d categories)...") % number)

        # get rid of any earlier attempts
        grass.try_remove(sqltmp)

        f = open(sqltmp, 'w')

        # do the stats
        p = grass.pipe_command('r.univar',
                               flags='t' + extstat,
                               map=raster,
                               zones=rastertmp,
                               percentile=percentile,
                               sep=';')

        first_line = 1

        f.write("{0}\n".format(grass.db_begin_transaction(fi['driver'])))
        for line in p.stdout:
            if first_line:
                first_line = 0
                continue

            vars = decode(line).rstrip('\r\n').split(';')

            f.write("UPDATE %s SET" % fi['table'])
            first_var = 1
            for colname in colnames:
                variable = colname.replace("%s_" % colprefix, '', 1)
                if dbfdriver:
                    variable = variables_dbf[variable]
                i = variables[variable]
                value = vars[i]
                # convert nan, +nan, -nan, inf, +inf, -inf, Infinity, +Infinity,
                # -Infinity to NULL
                if value.lower().endswith('nan') or 'inf' in value.lower():
                    value = 'NULL'
                if not first_var:
                    f.write(" , ")
                else:
                    first_var = 0
                f.write(" %s=%s" % (colname, value))

            f.write(" WHERE %s=%s;\n" % (fi['key'], vars[0]))
        f.write("{0}\n".format(grass.db_commit_transaction(fi['driver'])))
        p.wait()
        f.close()

        grass.message(_("Updating the database ..."))
        exitcode = 0
        try:
            grass.run_command('db.execute',
                              input=sqltmp,
                              database=fi['database'],
                              driver=fi['driver'])
            grass.verbose(
                (_("Statistics calculated from raster map <{raster}>"
                   " and uploaded to attribute table"
                   " of vector map <{vector}>.").format(raster=raster,
                                                        vector=vector)))
        except CalledModuleError:
            grass.warning(
                _("Failed to upload statistics to attribute table of vector map <%s>."
                  ) % vector)
            exitcode = 1

            sys.exit(exitcode)
Exemple #24
0
def calculate_lfp(input, output, coords):
    prefix = "r_lfp_%d_" % os.getpid()

    # create the outlet vector map
    outlet = prefix + "outlet"
    p = grass.feed_command("v.in.ascii",
                           overwrite=True,
                           input="-",
                           output=outlet,
                           separator=",")
    p.stdin.write(coords)
    p.stdin.close()
    p.wait()
    if p.returncode != 0:
        grass.fatal(_("Cannot create the outlet vector map"))

    # convert the outlet vector map to raster
    try:
        grass.run_command("v.to.rast",
                          overwrite=True,
                          input=outlet,
                          output=outlet,
                          use="cat",
                          type="point")
    except CalledModuleError:
        grass.fatal(_("Cannot convert the outlet vector to raster"))

    # calculate the downstream flow length
    flds = prefix + "flds"
    try:
        grass.run_command("r.stream.distance",
                          overwrite=True,
                          flags="om",
                          stream_rast=outlet,
                          direction=input,
                          method="downstream",
                          distance=flds)
    except CalledModuleError:
        grass.fatal(_("Cannot calculate the downstream flow length"))

    # calculate the upstream flow length
    flus = prefix + "flus"
    try:
        grass.run_command("r.stream.distance",
                          overwrite=True,
                          flags="o",
                          stream_rast=outlet,
                          direction=input,
                          method="upstream",
                          distance=flus)
    except CalledModuleError:
        grass.fatal(_("Cannot calculate the upstream flow length"))

    # calculate the sum of downstream and upstream flow lengths
    fldsus = prefix + "fldsus"
    try:
        grass.run_command("r.mapcalc",
                          overwrite=True,
                          expression="%s=%s+%s" % (fldsus, flds, flus))
    except CalledModuleError:
        grass.fatal(
            _("Cannot calculate the sum of downstream and upstream flow lengths"
              ))

    # find the longest flow length
    p = grass.pipe_command("r.info", flags="r", map=fldsus)
    max = ""
    for line in p.stdout:
        line = line.rstrip("\n")
        if line.startswith("max="):
            max = line.split("=")[1]
            break
    p.wait()
    if p.returncode != 0 or max == "":
        grass.fatal(_("Cannot find the longest flow length"))

    min = float(max) - 0.0005

    # extract the longest flow path
    lfp = prefix + "lfp"
    try:
        grass.run_command("r.mapcalc",
                          overwrite=True,
                          expression="%s=if(%s>=%f, 1, null())" %
                          (lfp, fldsus, min))
    except CalledModuleError:
        grass.fatal(_("Cannot create the longest flow path raster map"))

    # thin the longest flow path raster map
    try:
        grass.run_command("r.thin", input=lfp, output=output)
    except CalledModuleError:
        grass.fatal(_("Cannot thin the longest flow path raster map"))

    # remove intermediate outputs
    grass.run_command("g.remove",
                      flags="f",
                      type="raster,vector",
                      pattern="%s*" % prefix)

    # write metadata
    tmphist = grass.tempfile()
    f = open(tmphist, "w+")
    f.write(os.environ["CMDLINE"])
    f.close()

    grass.run_command("r.support",
                      map=output,
                      title="Longest flow path",
                      loadhistory=tmphist,
                      description="generated by r.lfp")
    grass.try_remove(tmphist)
def main():
    global tmp, nuldev
    nuldev = file(os.devnull, 'w')

    ## setup temporary files
    tmp = grass.tempfile()
    tmpf = 'v_net_neighbors'

    inmap = options['input']
    outfile = options['dump']

    # check if input file exists
    if not grass.find_file(inmap, element = 'vector')['file']:
        grass.fatal(_("<%s> does not exist.") % inmap)

    # check for table in net vector map
    try:
        f = grass.vector_db(inmap)[2]
    except KeyError:
        grass.run_command('v.db.addtable', _map = inmap, layer = 2,
                          quiet = True, stderr = nuldev)
        
    ## extract temp nodes and lines
    nodes = tmpf + '_nodes'
    lines = tmpf + '_lines'

    iflines = grass.vector_info_topo(inmap)['lines']
    ifbounds = grass.vector_info_topo(inmap)['boundaries']
    if iflines != 0:
        vect_type = 'line'
    if ifbounds != 0:
        vect_type = 'boundary'
    
    if iflines != 0 and ifbounds != 0:
        grass.fatal(_("Input net vector map must have lines OR boundaries, not both"))

    grass.run_command('v.extract', input = inmap, output = nodes, layer = 2, 
                      _type = 'point', flags = 't', quiet = True, stderr = nuldev)
    grass.run_command('v.extract', input = inmap, output = lines,  
                      _type = vect_type, flags = 't', quiet = True, stderr = nuldev)

    ## filter nodes on line intersections if with '-i' flag 
    if flags['i']:
        p = grass.pipe_command('v.net', _input = inmap, operation = 'nreport',
                               quiet = True, stderr = nuldev)
        c  = p.communicate()[0].strip().split('\n')
        filt = [elem for elem in c if ',' in elem]

        fnodes = []
        
        for x in filt:
            spl = x.split(' ')
            fnodes.append(spl[0])

        fnodes_str = ','.join(fnodes)
        
        nsel = tmpf + '_nsel'
        grass.run_command('v.extract', _input = nodes, _list = fnodes_str, 
                          output = nsel, layer = 2, _type = 'point',
                          quiet = True, stderr = nuldev)

        grass.run_command('g.rename', vect = (nsel,nodes), overwrite = True, 
                          quiet = True, stderr = nuldev)
        
        
    if not flags['p']:
        grass.run_command('v.db.addcol', _map = inmap, layer = 2, 
                          columns = 'neigh_node varchar(255)', 
                          quiet = True, stderr = nuldev)

    ## main cycle (extract every node and make 2 selects)
    out_dict = {}

    p = grass.pipe_command('v.category', _input = nodes, opt = 'print', layer = 2, 
                           _type = 'point', quiet = True, stderr = nuldev)
    c = p.communicate()[0].strip().split('\n')
    for cat in c:
        icat = int(cat)

        nnode = nodes + cat
        grass.run_command('v.extract', _input = nodes, _list = cat, 
                          output = nnode, layer = 2, _type = 'point',
                          flags = 't', quiet = True, stderr = nuldev)

        linode = nnode + '_lines'
        grass.run_command('v.select', ain = lines, _bin = nnode, 
                          blayer = 2, output = linode, 
                          operator = 'overlap', quiet = True, stderr = nuldev)
        
        linode_pts = linode + '_pts'
        grass.run_command('v.select', ain = nodes, alayer = 2, 
                          _bin = linode, output = linode_pts, 
                          operator = 'overlap', quiet = True, stderr = nuldev)
        
        pcat = grass.pipe_command('v.category', _input = linode_pts, layer = 2,
                                  opt = 'print', quiet = True, stderr = nuldev)
        ccat = pcat.communicate()[0].strip().split('\n')
        ccat.remove(cat)
        
        ncat_list = []
        ncat_list.append(ccat)

        str_db = ','.join(map(str, ncat_list))
        str_db1 = str_db.replace("[", "").replace("]", "").replace("'", "").replace(" ", "")

        out_dict[icat] = str_db1
        
        if not flags['p']:
            grass.run_command('v.db.update', _map = inmap, layer = 2, 
                              column = 'neigh_node', value = '%s' % (str_db1), 
                              where = "cat = %d" % (icat), 
                              quiet = True, stderr = nuldev )
        
    ## output to stdout / file
    tmp3 = tmp + '.out'
    outf2 = file(tmp3, 'w')
    for key in sorted(out_dict.iterkeys()):
        val = out_dict[key]
        print >> outf2, "%s %s" % (key,val)
    outf2.close()
    
    if flags['p']:
        with open(tmp3, 'rb') as f:
            print f.read()

    if outfile:
        shutil.copyfile(tmp3, outfile)
                

    return 0
Exemple #26
0
def main():
    mapname = options['map']
    option = options['option']
    layer = options['layer']
    units = options['units']

    nuldev = file(os.devnull, 'w')

    if not grass.find_file(mapname, 'vector')['file']:
        grass.fatal(_("Vector map <%s> not found") % mapname)

    colnames = grass.vector_columns(mapname,
                                    layer,
                                    getDict=False,
                                    stderr=nuldev)
    if not colnames:
        colnames = ['cat']

    if option == 'coor':
        columns = ['dummy1', 'dummy2', 'dummy3']
        extracolnames = ['x', 'y', 'z']
    else:
        columns = ['dummy1']
        extracolnames = [option]

    if units in ['p', 'percent']:
        unitsp = 'meters'
    elif units:
        unitsp = units
    else:
        unitsp = None

    # NOTE: we suppress -1 cat and 0 cat
    if colnames:
        p = grass.pipe_command('v.db.select',
                               quiet=True,
                               flags='c',
                               map=mapname,
                               layer=layer)
        records1 = []
        for line in p.stdout:
            cols = line.rstrip('\r\n').split('|')
            if cols[0] == '0':
                continue
            records1.append([int(cols[0])] + cols[1:])
        p.wait()
        if p.returncode != 0:
            sys.exit(1)

        records1.sort()

        if len(records1) == 0:
            try:
                f = grass.vector_db(map=mapname)[int(layer)]
                grass.fatal(
                    _("There is a table connected to input vector map '%s', but"
                      "there are no categories present in the key column '%s'. Consider using"
                      "v.to.db to correct this.") % (mapname, f['key']))
            except KeyError:
                pass

        #fetch the requested attribute sorted by cat:
        p = grass.pipe_command('v.to.db',
                               flags='p',
                               quiet=True,
                               map=mapname,
                               option=option,
                               columns=columns,
                               layer=layer,
                               units=unitsp)
        records2 = []
        for line in p.stdout:
            fields = line.rstrip('\r\n').split('|')
            if fields[0] in ['cat', '-1', '0']:
                continue
            records2.append([int(fields[0])] + fields[1:-1] +
                            [float(fields[-1])])
        p.wait()
        records2.sort()

        #make pre-table
        # len(records1) may not be the same as len(records2) because
        # v.db.select can return attributes that are not linked to features.
        records3 = []
        for r2 in records2:
            records3.append(
                filter(lambda r1: r1[0] == r2[0], records1)[0] + r2[1:])
    else:
        records1 = []
        p = grass.pipe_command('v.category',
                               inp=mapname,
                               layer=layer,
                               option='print')
        for line in p.stdout:
            field = int(line.rstrip())
            if field > 0:
                records1.append(field)
        p.wait()
        records1.sort()
        records1 = uniq(records1)

        #make pre-table
        p = grass.pipe_command('v.to.db',
                               flags='p',
                               map=mapname,
                               option=option,
                               columns=columns,
                               layer=layer,
                               units=unitsp)
        records3 = []
        for line in p.stdout:
            fields = line.split('|')
            if fields[0] in ['cat', '-1', '0']:
                continue
            records3.append([int(fields[0])] + fields[1:])
        p.wait()
        records3.sort()

    # print table header
    sys.stdout.write('|'.join(colnames + extracolnames) + '\n')

    #make and print the table:
    numcols = len(colnames) + len(extracolnames)

    # calculate percents if requested
    if units != '' and units in ['p', 'percent']:
        # calculate total area value
        areatot = 0
        for r in records3:
            areatot += float(r[-1])

        # calculate area percentages
        records4 = [float(r[-1]) * 100 / areatot for r in records3]
        records3 = [r1 + [r4] for r1, r4 in zip(records1, records4)]

    # sort results
    if options['sort']:
        if options['sort'] == 'asc':
            records3.sort(key=lambda r: r[-1])
        else:
            records3.sort(key=lambda r: r[-1], reverse=True)

    for r in records3:
        sys.stdout.write('|'.join(map(str, r)) + '\n')
Exemple #27
0
def output_centerline(river, stations, elev, outfile):
    """ 
	Output the river network, including centerline for each reach
	and coordinates for all stations along each reach
	"""

    # Begin with the list of reach cats
    rc = grass.read_command('v.category',
                            input=river,
                            type="line",
                            option="print")
    reach_cats = rc.strip().split("\n")

    outfile.write("BEGIN STREAM NETWORK:\n")
    # Now get points from the river vector, one pair for each reach
    for i in range(len(reach_cats)):
        where_cond = "cat=" + str(reach_cats[i])
        riv = grass.read_command('v.db.select',
                                 map=river,
                                 separator=" ",
                                 columns="cat,start_x,start_y,end_x,end_y",
                                 where=where_cond,
                                 flags="c")
        riv_pts = riv.strip().split(" ")
        pi, x1, y1, x2, y2 = riv_pts[0], riv_pts[1], riv_pts[2], riv_pts[
            3], riv_pts[4]
        # Give the start point a point id of "cat"1, and the endpoint an id of "cat"2
        pi1 = pi + "1"
        pi2 = pi + "2"
        # Get elevation of each endpoint from the elev raster
        coords = x1 + "," + y1
        e = grass.read_command('r.what',
                               map=elev,
                               coordinates=coords,
                               separator=",")
        start_elev = e.split(",")[3].rstrip()
        coords = x2 + "," + y2
        e = grass.read_command('r.what',
                               map=elev,
                               coordinates=coords,
                               separator=",")
        end_elev = e.split(",")[3].rstrip()
        outfile.write(" ENDPOINT: " + x1 + "," + y1 + "," + start_elev + "," +
                      pi1 + "\n")
        outfile.write(" ENDPOINT: " + x2 + "," + y2 + "," + end_elev + "," +
                      pi2 + "\n")

    # Loop thru the reach_cats again, and output a REACH: section for each reach,
    # with all points for that reach
    for i in range(len(reach_cats)):
        outfile.write(" REACH:\n")
        outfile.write("   STREAM ID: %s\n" % river)
        reach_id = str(reach_cats[i])
        outfile.write("   REACH ID: %s\n" % reach_id)
        # Get the FROM POINT and TO POINT ids just like above
        where_cond = "cat=" + str(reach_cats[i])
        riv = grass.read_command('v.db.select',
                                 map=river,
                                 separator=" ",
                                 columns="cat,start_x,end_x,start_y,end_y",
                                 where=where_cond,
                                 flags="c")
        r_pts = riv.strip().split(" ")
        pi, x1, y1, x2, y2 = r_pts[0], r_pts[1], r_pts[2], r_pts[3], r_pts[4]
        # Give the start point a point id of "cat"1, and the endpoint a n id of "cat"2
        pi1 = pi + "1"
        pi2 = pi + "2"
        outfile.write("   FROM POINT: %s\n" % pi1)
        outfile.write("   TO POINT: %s\n" % pi2)

        # Now the actual points along centerline
        outfile.write("   CENTERLINE:\n")
        # loop thru the stations point vector to get each station's x,y and id
        reach_cond = "reach_id=" + reach_cats[i]
        p = grass.pipe_command('v.db.select',
                               map=stations,
                               where=reach_cond,
                               quiet=True,
                               flags="c")
        st_list = []
        for line in p.stdout:
            st = line.strip().split('|')
            s, x, y = st[0], st[1], st[2]
            st_list.append([s, x, y])

        p.stdout.close()
        p.wait()
        # Now write out all station points to the CENTERLINE section
        # Go thru the st_list in reverse order so that the centerline is from upstream to downstream
        for i in range(len(st_list) - 1, -1, -1):
            outfile.write("	" + st_list[i][1] + "," + st_list[i][2] +
                          ",NULL," + st_list[i][0] + "\n")

        outfile.write(" END:\n")

    # Close STREAM NETWORK section
    outfile.write("END STREAM NETWORK:\n\n")
    # These map and columns have to exist in the current mapset's search path
    firms_map = 'produnits_%d' % annee
    nace_column = 'cd_nace_%d' % annee
    turnover_column = 'turnover_estim'
    for nace2 in gscript.read_command('v.db.select',
                                      map=firms_map,
                                      column="substr(%s, 1, 2)" % nace_column,
                                      group="substr(%s, 1, 2)" % nace_column,
                                      where="%s <> ''" % nace_column,
                                      flags='c',
                                      quiet=True).splitlines():
        print nace2
        pin = gscript.pipe_command(
            'v.db.select',
            map=firms_map,
            column="x,y,%s" % turnover_column,
            where="substr(%s, 1, 2) = '%s' AND %s >= 0" %
            (nace_column, nace2, turnover_column),
            flags='c',
            quiet=True)
        total_turnover_map = 'turnover_%d_%s' % (annee, nace2)
        p = gscript.start_command('r.in.xyz',
                                  input_='-',
                                  stdin=pin.stdout,
                                  method='sum',
                                  type_='DCELL',
                                  output=total_turnover_map,
                                  quiet=True,
                                  overwrite=True)
        if p.wait() is not 0:
            gscript.fatal("Error in r.in.xyz with nace %s" % nace2)
Exemple #29
0
def main(options, flags):

    gisbase = os.getenv("GISBASE")
    if not gisbase:
        gs.fatal(_("$GISBASE not defined"))
        return 0

    # Reference / sample area or points
    ref_rast = options["ref_rast"]
    ref_vect = options["ref_vect"]
    if ref_rast:
        reftype = gs.raster_info(ref_rast)
        if reftype["datatype"] != "CELL":
            gs.fatal(_("The ref_rast map must have type CELL (integer)"))
        if (reftype["min"] != 0 and reftype["min"] != 1) or reftype["max"] != 1:
            gs.fatal(
                _(
                    "The ref_rast map must be a binary raster,"
                    " i.e. it should contain only values 0 and 1 or 1 only"
                    " (now the minimum is {} and maximum is {})".format(
                        reftype["min"], reftype["max"]
                    )
                )
            )

    # old environmental layers & variable names
    REF = options["env"]
    REF = REF.split(",")
    raster_exists(REF)
    ipn = [z.split("@")[0] for z in REF]
    ipn = [x.lower() for x in ipn]

    # new environmental variables
    PROJ = options["env_proj"]
    if not PROJ:
        RP = False
        PROJ = REF
    else:
        RP = True
        PROJ = PROJ.split(",")
        raster_exists(PROJ)
        if len(PROJ) != len(REF) and len(PROJ) != 0:
            gs.fatal(
                _(
                    "The number of reference and predictor variables"
                    " should be the same. You provided {} reference and {}"
                    " projection variables".format(len(REF), len(PROJ))
                )
            )

    # output layers
    opl = options["output"]
    opc = opl + "_MES"
    ipi = [opl + "_" + i for i in ipn]

    # flags
    flm = flags["m"]
    flk = flags["k"]
    fln = flags["n"]
    fli = flags["i"]
    flc = flags["c"]

    # digits / precision
    digits = int(options["digits"])
    digits2 = pow(10, digits)

    # get current region settings, to compare to new ones later
    region_1 = gs.parse_command("g.region", flags="g")

    # Text for history in metadata
    opt2 = dict((k, v) for k, v in options.iteritems() if v)
    hist = " ".join("{!s}={!r}".format(k, v) for (k, v) in opt2.iteritems())
    hist = "r.mess {}".format(hist)
    unused, tmphist = tempfile.mkstemp()
    with open(tmphist, "w") as text_file:
        text_file.write(hist)

    # Create reference layer if not defined
    if not ref_rast and not ref_vect:
        ref_rast = tmpname("tmp0")
        gs.mapcalc("$i = if(isnull($r),null(),1)", i=ref_rast, r=REF[0], quiet=True)

    # Create the recode table - Reference distribution is raster
    citiam = gs.find_file(name="MASK", element="cell", mapset=gs.gisenv()["MAPSET"])
    if citiam["fullname"]:
        rname = tmpname("tmp3")
        gs.mapcalc("$rname = MASK", rname=rname, quiet=True)

    if ref_rast:
        vtl = ref_rast

        # Create temporary layer based on reference layer
        tmpf0 = tmpname("tmp2")
        gs.mapcalc("$tmpf0 = int($vtl * 1)", vtl=vtl, tmpf0=tmpf0, quiet=True)
        gs.run_command("r.null", map=tmpf0, setnull=0, quiet=True)
        if citiam["fullname"]:
            gs.run_command("r.mask", flags="r", quiet=True)
        for i in xrange(len(REF)):

            # Create mask based on combined MASK/reference layer
            gs.run_command("r.mask", raster=tmpf0, quiet=True)

            # Calculate the frequency distribution
            tmpf1 = tmpname("tmp4")
            gs.mapcalc(
                "$tmpf1 = int($dignum * $inplay)",
                tmpf1=tmpf1,
                inplay=REF[i],
                dignum=digits2,
                quiet=True,
            )
            p = gs.pipe_command(
                "r.stats", quiet=True, flags="cn", input=tmpf1, sort="asc", sep=";"
            )
            stval = {}
            for line in p.stdout:
                [val, count] = line.strip(os.linesep).split(";")
                stval[float(val)] = float(count)
            p.wait()
            sstval = sorted(stval.items(), key=operator.itemgetter(0))
            sstval = np.matrix(sstval)
            a = np.cumsum(np.array(sstval), axis=0)
            b = np.sum(np.array(sstval), axis=0)
            c = a[:, 1] / b[1] * 100

            # Remove tmp mask and set region to env_proj if needed
            gs.run_command("r.mask", quiet=True, flags="r")
            if RP:
                gs.use_temp_region()
                gs.run_command("g.region", quiet=True, raster=PROJ[0])

            # get new region settings, to compare to original ones later
            region_2 = gs.parse_command("g.region", flags="g")

            # Get min and max values for recode table (based on full map)
            tmpf2 = tmpname("tmp5")
            gs.mapcalc(
                "$tmpf2 = int($dignum * $inplay)",
                tmpf2=tmpf2,
                inplay=PROJ[i],
                dignum=digits2,
                quiet=True,
            )
            d = gs.parse_command("r.univar", flags="g", map=tmpf2, quiet=True)

            # Create recode rules
            Dmin = int(d["min"])
            Dmax = int(d["max"])
            envmin = np.min(np.array(sstval), axis=0)[0]
            envmax = np.max(np.array(sstval), axis=0)[0]

            if Dmin < envmin:
                e1 = Dmin - 1
            else:
                e1 = envmin - 1
            if Dmax > envmax:
                e2 = Dmax + 1
            else:
                e2 = envmax + 1

            a1 = np.hstack([(e1), np.array(sstval.T[0])[0, :]])
            a2 = np.hstack([np.array(sstval.T[0])[0, :] - 1, (e2)])
            b1 = np.hstack([(0), c])

            fd2, tmprule = tempfile.mkstemp(suffix=ipn[i])
            with open(tmprule, "w") as text_file:
                for k in np.arange(0, len(b1.T)):
                    text_file.write(
                        "%s:%s:%s\n" % (str(int(a1[k])), str(int(a2[k])), str(b1[k]))
                    )

            # Create the recode layer and calculate the IES
            compute_ies(tmprule, ipi[i], tmpf2, envmin, envmax)
            gs.run_command(
                "r.support",
                map=ipi[i],
                title="IES {}".format(REF[i]),
                units="0-100 (relative score",
                description="Environmental similarity {}".format(REF[i]),
                loadhistory=tmphist,
            )

            # Clean up
            os.close(fd2)
            os.remove(tmprule)

            # Change region back to original
            gs.del_temp_region()

    # Create the recode table - Reference distribution is vector
    else:
        vtl = ref_vect

        # Copy point layer and add columns for variables
        tmpf0 = tmpname("tmp7")
        gs.run_command(
            "v.extract", quiet=True, flags="t", input=vtl, type="point", output=tmpf0
        )
        gs.run_command("v.db.addtable", quiet=True, map=tmpf0)

        # TODO: see if there is a more efficient way to handle the mask
        if citiam["fullname"]:
            gs.run_command("r.mask", quiet=True, flags="r")

        # Upload raster values and get value in python as frequency table
        sql1 = "SELECT cat FROM {}".format(str(tmpf0))
        cn = len(np.hstack(db.db_select(sql=sql1)))
        for m in xrange(len(REF)):

            # Set mask back (this means that points outside the mask will
            # be ignored in the computation of the frequency distribution
            # of the reference variabele env(m))
            if citiam["fullname"]:
                gs.run_command("g.copy", raster=[rname, "MASK"], quiet=True)

            # Compute frequency distribution of variable(m)
            mid = str(m)
            laytype = gs.raster_info(REF[m])["datatype"]
            if laytype == "CELL":
                columns = "envvar_{} integer".format(str(mid))
            else:
                columns = "envvar_%s double precision" % mid
            gs.run_command("v.db.addcolumn", map=tmpf0, columns=columns, quiet=True)
            sql2 = "UPDATE {} SET envvar_{} = NULL".format(str(tmpf0), str(mid))
            gs.run_command("db.execute", sql=sql2, quiet=True)
            coln = "envvar_%s" % mid
            gs.run_command(
                "v.what.rast",
                quiet=True,
                map=tmpf0,
                layer=1,
                raster=REF[m],
                column=coln,
            )
            sql3 = (
                "SELECT {0}, count({0}) from {1} WHERE {0} IS NOT NULL "
                "GROUP BY {0} ORDER BY {0}"
            ).format(coln, tmpf0)
            volval = np.vstack(db.db_select(sql=sql3))
            volval = volval.astype(np.float, copy=False)
            a = np.cumsum(volval[:, 1], axis=0)
            b = np.sum(volval[:, 1], axis=0)
            c = a / b * 100

            # Check for point without values
            if b < cn:
                gs.info(
                    _(
                        "Please note that there were {} points without "
                        "value. This is probably because they are outside "
                        "the computational region or mask".format((cn - b))
                    )
                )

            # Set region to env_proj layers (if different from env) and remove
            # mask (if set above)
            if citiam["fullname"]:
                gs.run_command("r.mask", quiet=True, flags="r")
            if RP:
                gs.use_temp_region()
                gs.run_command("g.region", quiet=True, raster=PROJ[0])
            region_2 = gs.parse_command("g.region", flags="g")

            # Multiply env_proj layer with dignum
            tmpf2 = tmpname("tmp8")
            gs.mapcalc(
                "$tmpf2 = int($dignum * $inplay)",
                tmpf2=tmpf2,
                inplay=PROJ[m],
                dignum=digits2,
                quiet=True,
            )

            # Calculate min and max values of sample points and raster layer
            envmin = int(min(volval[:, 0]) * digits2)
            envmax = int(max(volval[:, 0]) * digits2)
            Drange = gs.read_command("r.info", flags="r", map=tmpf2)
            Drange = str.splitlines(Drange)
            Drange = np.hstack([i.split("=") for i in Drange])
            Dmin = int(Drange[1])
            Dmax = int(Drange[3])

            if Dmin < envmin:
                e1 = Dmin - 1
            else:
                e1 = envmin - 1
            if Dmax > envmax:
                e2 = Dmax + 1
            else:
                e2 = envmax + 1

            a0 = volval[:, 0] * digits2
            a0 = a0.astype(np.int, copy=False)
            a1 = np.hstack([(e1), a0])
            a2 = np.hstack([a0 - 1, (e2)])
            b1 = np.hstack([(0), c])

            fd3, tmprule = tempfile.mkstemp(suffix=ipn[m])
            with open(tmprule, "w") as text_file:
                for k in np.arange(0, len(b1)):
                    rtmp = "{}:{}:{}\n".format(
                        str(int(a1[k])), str(int(a2[k])), str(b1[k])
                    )
                    text_file.write(rtmp)

            # Create the recode layer and calculate the IES
            compute_ies(tmprule, ipi[m], tmpf2, envmin, envmax)
            gs.run_command(
                "r.support",
                map=ipi[m],
                title="IES {}".format(REF[m]),
                units="0-100 (relative score",
                description="Environmental similarity {}".format(REF[m]),
                loadhistory=tmphist,
            )

            # Clean up
            os.close(fd3)
            os.remove(tmprule)

            # Change region back to original
            gs.del_temp_region()

    # Calculate MESS statistics
    # Set region to env_proj layers (if different from env)
    # Note: this changes the region, to ensure the newly created layers
    # are actually visible to the user. This goes against normal practise
    # There will be a warning.
    if RP:
        gs.run_command("g.region", quiet=True, raster=PROJ[0])

    # MES
    gs.run_command("r.series", quiet=True, output=opc, input=ipi, method="minimum")
    gs.write_command("r.colors", map=opc, rules="-", stdin=COLORS_MES, quiet=True)

    # Write layer metadata
    gs.run_command(
        "r.support",
        map=opc,
        title="Areas with novel conditions",
        units="0-100 (relative score",
        description="The multivariate environmental similarity" "(MES)",
        loadhistory=tmphist,
    )

    # Area with negative MES
    if fln:
        mod1 = "{}_novel".format(opl)
        gs.mapcalc("$mod1 = int(if( $opc < 0, 1, 0))", mod1=mod1, opc=opc, quiet=True)

        # Write category labels
        gs.write_command(
            "r.category", map=mod1, rules="-", stdin=RECL_MESNEG, quiet=True
        )

        # Write layer metadata
        gs.run_command(
            "r.support",
            map=mod1,
            title="Areas with novel conditions",
            units="-",
            source1="Based on {}".format(opc),
            description="1 = novel conditions, 0 = within range",
            loadhistory=tmphist,
        )

    # Most dissimilar variable (MoD)
    if flm:
        tmpf4 = tmpname("tmp9")
        mod2 = "{}_MoD".format(opl)
        gs.run_command(
            "r.series", quiet=True, output=tmpf4, input=ipi, method="min_raster"
        )
        gs.mapcalc("$mod2 = int($tmpf4)", mod2=mod2, tmpf4=tmpf4, quiet=True)

        fd4, tmpcat = tempfile.mkstemp()
        with open(tmpcat, "w") as text_file:
            for cats in xrange(len(ipi)):
                text_file.write("{}:{}\n".format(str(cats), REF[cats]))
        gs.run_command("r.category", quiet=True, map=mod2, rules=tmpcat, separator=":")
        os.close(fd4)
        os.remove(tmpcat)

        # Write layer metadata
        gs.run_command(
            "r.support",
            map=mod2,
            title="Most dissimilar variable (MoD)",
            units="-",
            source1="Based on {}".format(opc),
            description="Name of most dissimilar variable",
            loadhistory=tmphist,
        )

    # sum(IES), where IES < 0
    if flk:
        mod3 = "{}_SumNeg".format(opl)
        c0 = -0.01 / digits2
        gs.run_command(
            "r.series",
            quiet=True,
            input=ipi,
            method="sum",
            range=("-inf", c0),
            output=mod3,
        )
        gs.write_command("r.colors", map=mod3, rules="-", stdin=COLORS_MES, quiet=True)

        # Write layer metadata
        gs.run_command(
            "r.support",
            map=mod3,
            title="Sum of negative IES values",
            units="-",
            source1="Based on {}".format(opc),
            description="Sum of negative IES values",
            loadhistory=tmphist,
        )

    # Number of layers with negative values
    if flc:
        tmpf5 = tmpname("tmp10")
        mod4 = "{}_CountNeg".format(opl)
        MinMes = gs.read_command("r.info", quiet=True, flags="r", map=opc)
        MinMes = str.splitlines(MinMes)
        MinMes = float(np.hstack([i.split("=") for i in MinMes])[1])
        c0 = -0.0001 / digits2
        gs.run_command(
            "r.series",
            quiet=True,
            input=ipi,
            output=tmpf5,
            method="count",
            range=(MinMes, c0),
        )
        gs.mapcalc("$mod4 = int($tmpf5)", mod4=mod4, tmpf5=tmpf5, quiet=True)

        # Write layer metadata
        gs.run_command(
            "r.support",
            map=mod4,
            title="Number of layers with negative values",
            units="-",
            source1="Based on {}".format(opc),
            description="Number of layers with negative values",
            loadhistory=tmphist,
        )

    # Remove IES layers
    if fli:
        gs.run_command("g.remove", quiet=True, flags="f", type="raster", name=ipi)
    # Clean up tmp file
    os.remove(tmphist)

    gs.message(_("Finished ...\n"))
    if region_1 != region_2:
        gs.message(
            _(
                "\nPlease note that the region has been changes to match"
                " the set of projection (env_proj) variables.\n"
            )
        )
Exemple #30
0
def output_xsections(xsects, outfile, elev, res, river):
    """
	Create the cross section profiles by first making a points vector from the cross sections
	loop thru the section_ids and use v.out.ascii to get the points for each cross section.
	Feed these points into r.profile to get lists of the coords and elevation at each spot along the xsection,
	and output these to the CROSS-SECTION paragraph
	"""

    # Prepare tmp vector maps to hold the points from the cross sections
    proc = os.getpid()
    xsect_pts = "tmp_xsect_pts_" + str(proc)
    #xsect_pts2="tmp_xsect_pts2_"+str(proc)
    # v.to.points returns all points on the same cross section with the same cat value
    grass.run_command('v.to.points',
                      input=xsects,
                      output=xsect_pts,
                      use="vertex",
                      quiet=True)
    outfile.write("\n")
    outfile.write("BEGIN CROSS-SECTIONS:\n")

    # Get the list of station ids with the reaches
    # Layer 1 contains one cat for all points on the same xsect line,
    # so v.db.select returns one row for each xsect line (not for each point on the line)
    st = grass.pipe_command('v.db.select',
                            map=xsect_pts,
                            layer=1,
                            columns="reach,station_id",
                            flags="c",
                            quiet=True)
    station_ids = []
    for line in st.stdout:
        station = line.rstrip('\n').split("|")
        r, s = station[0], station[1]
        station_ids.append([r, s])

    st.stdout.close()
    st.wait()

    # Now loop thru those stations to create the CUTLINE and SURFACE section
    for i in range(len(station_ids)):
        station_id = station_ids[i][1].strip('\n')
        reach = station_ids[i][0].rstrip('\n')
        process_msg = "Processing reach: " + reach + " at station id: " + station_id
        grass.message(process_msg)
        outfile.write(" CROSS-SECTION:\n")
        outfile.write("   STREAM ID: %s\n" % river)
        outfile.write("   REACH ID: %s\n" % reach)
        outfile.write("   STATION: %s\n" % station_id)

        # get point coords from this reach/station and print out CUTLINE: section
        # Save this output also for next SURFACE: section
        station_cond = "station_id=" + station_id
        p = grass.pipe_command('v.out.ascii',
                               input=xsect_pts,
                               columns="reach,station_id",
                               where=station_cond,
                               separator=",",
                               layer=1,
                               quiet=True)
        station_pts = []
        for line in p.stdout:
            st = line.rstrip('\n').split(',')
            station_pts.append(st)

        p.stdout.close()
        p.wait()

        outfile.write("   CUTLINE:\n")
        for j in range(len(station_pts)):
            x, y = station_pts[j][0], station_pts[j][1]
            outfile.write("	 " + x + "," + y + "\n")

        # Now run the points thru r.profile, and get the elevations
        # and print elevations to SURFACE LINE: section
        outfile.write("   SURFACE LINE:\n")
        profile_pts = []
        for k in range(len(station_pts)):
            x, y = station_pts[k][0], station_pts[k][1]
            profile_pts.append([x, y])

        pp = grass.pipe_command('r.profile',
                                input=elev,
                                coordinates=profile_pts,
                                resolution=res,
                                flags="g",
                                quiet=True)
        for line in pp.stdout:
            l = line.rstrip('\n').split(" ")
            # The r.profile output has x,y in first two columns and elev in 4th column
            outfile.write("	 " + l[0] + "," + l[1] + "," + l[3] + "\n")
        pp.stdout.close()
        pp.wait()

        # CLose this CROSS-SECTION paragraph
        outfile.write(" END:\n\n")

    outfile.write("END CROSS-SECTIONS:\n\n")

    # remove temp points file
    grass.message("Removing temp vector: %s" % (xsect_pts))
    grass.run_command('g.remove',
                      type='vector',
                      name=xsect_pts,
                      quiet=True,
                      flags="f")
Exemple #31
0
def calculate_lfp(input, output, idcol, id, coords, outlet, layer,
                  outletidcol):
    prefix = "r_lfp_%d_" % os.getpid()

    if id:
        ids = id.split(",")
        for i in range(0, len(ids)):
            try:
                ids[i] = int(ids[i])
            except:
                grass.fatal(_("Invalid ID '%s'") % ids[i])
    else:
        ids = []

    if coords:
        coords = coords.split(",")
    else:
        coords = []

    # append outlet points to coordinates
    if outlet:
        p = grass.pipe_command("v.report",
                               map=outlet,
                               layer=layer,
                               option="coor")
        for line in p.stdout:
            line = line.rstrip("\n")
            if line.startswith("cat|"):
                colnames = line.split("|")
                outletid_ind = -1
                for i in range(0, len(colnames)):
                    colname = colnames[i]
                    if colname == outletidcol:
                        outletid_ind = i
                    elif colname == "x":
                        x_ind = i
                    elif colname == "y":
                        y_ind = i
                if outletidcol and outletid_ind == -1:
                    grass.fatal(
                        _("Cannot find column <%s> in vector map <%s>") %
                        (outletidcol, outlet))
                continue
            cols = line.split("|")
            coords.extend([cols[x_ind], cols[y_ind]])
            if outletid_ind >= 0:
                try:
                    ids.extend([int(cols[outletid_ind])])
                except:
                    grass.fatal(_("Invalid ID '%s'") % ids[i])
        p.wait()
        if p.returncode != 0:
            grass.fatal(_("Cannot read outlet points"))

    if len(ids) > 0:
        if len(ids) > len(coords) / 2:
            grass.fatal(_("Too many IDs"))
        elif len(ids) < len(coords) / 2:
            grass.fatal(_("Too few IDs"))
        assign_id = True
    else:
        assign_id = False

    # create the output vector map
    try:
        grass.run_command("v.edit", map=output, tool="create")
    except CalledModuleError:
        grass.fatal(_("Cannot create the output vector map"))

    if assign_id:
        try:
            grass.run_command("v.db.addtable",
                              map=output,
                              columns="%s integer" % idcol)
        except CalledModuleError:
            grass.fatal(_("Cannot add a table to the output vector map"))

    for i in range(0, len(coords) / 2):
        cat = i + 1
        coor = "%s,%s" % (coords[2 * i], coords[2 * i + 1])
        if assign_id:
            id = ids[i]
            grass.message(_("Processing outlet %d at %s...") % (id, coor))
        else:
            grass.message(_("Processing outlet at %s...") % coor)

        # create the outlet vector map
        out = prefix + "out"
        p = grass.feed_command("v.in.ascii",
                               overwrite=True,
                               input="-",
                               output=out,
                               separator=",")
        p.stdin.write(coor)
        p.stdin.close()
        p.wait()
        if p.returncode != 0:
            grass.fatal(_("Cannot create the outlet vector map"))

        # convert the outlet vector map to raster
        try:
            grass.run_command("v.to.rast",
                              overwrite=True,
                              input=out,
                              output=out,
                              use="cat",
                              type="point")
        except CalledModuleError:
            grass.fatal(_("Cannot convert the outlet vector to raster"))

        # calculate the downstream flow length
        flds = prefix + "flds"
        try:
            grass.run_command("r.stream.distance",
                              overwrite=True,
                              flags="om",
                              stream_rast=out,
                              direction=input,
                              method="downstream",
                              distance=flds)
        except CalledModuleError:
            grass.fatal(_("Cannot calculate the downstream flow length"))

        # find the longest flow length
        p = grass.pipe_command("r.info", flags="r", map=flds)
        max = ""
        for line in p.stdout:
            line = line.rstrip("\n")
            if line.startswith("max="):
                max = line.split("=")[1]
                break
        p.wait()
        if p.returncode != 0 or max == "":
            grass.fatal(_("Cannot find the longest flow length"))

        threshold = float(max) - 0.0005

        # find the headwater cells
        heads = prefix + "heads"
        try:
            grass.run_command("r.mapcalc",
                              overwrite=True,
                              expression="%s=if(%s>=%f,1,null())" %
                              (heads, flds, threshold))
        except CalledModuleError:
            grass.fatal(_("Cannot find the headwater cells"))

        # create the headwater vector map
        try:
            grass.run_command("r.to.vect",
                              overwrite=True,
                              input=heads,
                              output=heads,
                              type="point")
        except CalledModuleError:
            grass.fatal(_("Cannot create the headwater vector map"))

        # calculate the longest flow path in vector format
        path = prefix + "path"
        try:
            grass.run_command("r.path",
                              overwrite=True,
                              input=input,
                              vector_path=path,
                              start_points=heads)
        except CalledModuleError:
            grass.fatal(_("Cannot create the longest flow path vector map"))

        # snap the outlet
        try:
            grass.run_command("r.to.vect",
                              overwrite=True,
                              input=out,
                              output=out,
                              type="point")
        except CalledModuleError:
            grass.fatal(_("Cannot snap the outlet"))

        # find the coordinates of the snapped outlet
        p = grass.pipe_command("v.to.db", flags="p", map=out, option="coor")
        coor = ""
        for line in p.stdout:
            line = line.rstrip("\n")
            if line == "cat|x|y|z":
                continue
            cols = line.split("|")
            coor = "%s,%s" % (cols[1], cols[2])
        p.wait()
        if p.returncode != 0 or coor == "":
            grass.fatal(_("Cannot find the coordinates of the snapped outlet"))

        # split the longest flow path at the outlet
        try:
            grass.run_command("v.edit", map=path, tool="break", coords=coor)
        except CalledModuleError:
            grass.fatal(_("Cannot split the longest flow path at the outlet"))

        # select the final longest flow path
        lfp = prefix + "lfp"
        try:
            grass.run_command("v.select",
                              overwrite=True,
                              ainput=path,
                              binput=heads,
                              output=lfp)
        except CalledModuleError:
            grass.fatal(_("Cannot select the final longest flow path"))

        lfp2 = lfp + "2"
        try:
            grass.run_command("v.category",
                              overwrite=True,
                              input=lfp,
                              output=lfp2,
                              option="del",
                              cat=-1)
            grass.run_command("v.category",
                              overwrite=True,
                              input=lfp2,
                              output=lfp,
                              option="add",
                              cat=cat,
                              step=0)
        except CalledModuleError:
            grass.fatal(_("Cannot add category %d") % cat)

        # copy the final longest flow path to the output map
        try:
            grass.run_command("v.edit",
                              flags="r",
                              map=output,
                              tool="copy",
                              bgmap=lfp,
                              cats=0)
        except CalledModuleError:
            grass.fatal(_("Cannot copy the final longest flow path"))

        if assign_id:
            try:
                grass.run_command("v.to.db",
                                  map=output,
                                  option="cat",
                                  columns="cat")
                grass.run_command("v.db.update",
                                  map=output,
                                  column=idcol,
                                  value=id,
                                  where="cat=%d" % cat)
            except CalledModuleError:
                grass.fatal(_("Cannot assign ID %d") % id)

    # remove intermediate outputs
    grass.run_command("g.remove",
                      flags="f",
                      type="raster,vector",
                      pattern="%s*" % prefix)

    # write history if supported
    version = grass.version()
    if version["revision"] != "exported":
        # the revision number is available
        version = int(version["revision"][1:])
    else:
        # some binary distributions don't build from the SVN repository and
        # revision is not available; use the libgis revision as a fallback in
        # this case
        version = int(version["libgis_revision"])

    if version >= 70740:
        # v.support -h added in r70740
        grass.run_command("v.support",
                          flags="h",
                          map=output,
                          cmdhist=os.environ["CMDLINE"])
Exemple #32
0
def main():
    global tmp, sqltmp, tmpname, nuldev, vector, rastertmp
    rastertmp = False
    #### setup temporary files
    tmp = grass.tempfile()
    sqltmp = tmp + ".sql"
    # we need a random name
    tmpname = grass.basename(tmp)

    nuldev = file(os.devnull, 'w')

    raster = options['raster']
    colprefix = options['column_prefix']
    vector = options['map']
    layer = options['layer']
    percentile = options['percentile']
    basecols = options['method'].split(',')

    ### setup enviro vars ###
    env = grass.gisenv()
    mapset = env['MAPSET']

    vs = vector.split('@')
    if len(vs) > 1:
        vect_mapset = vs[1]
    else:
        vect_mapset = mapset

    # does map exist in CURRENT mapset?
    if vect_mapset != mapset or not grass.find_file(vector, 'vector', mapset)['file']:
        grass.fatal(_("Vector map <%s> not found in current mapset") % vector)

    vector = vs[0]

    rastertmp = "%s_%s" % (vector, tmpname)

    # check the input raster map
    if not grass.find_file(raster, 'cell')['file']:
        grass.fatal(_("Raster map <%s> not found") % raster)

    # save current settings:
    grass.use_temp_region()

    # Temporarily aligning region resolution to $RASTER resolution
    # keep boundary settings
    grass.run_command('g.region', align=raster)

    grass.message(_("Preprocessing input data..."))
    try:
        grass.run_command('v.to.rast', input=vector, layer=layer, output=rastertmp,
                          use='cat', quiet=True)
    except CalledModuleError:
        grass.fatal(_("An error occurred while converting vector to raster"))

    # dump cats to file to avoid "too many argument" problem:
    p = grass.pipe_command('r.category', map=rastertmp, sep=';', quiet=True)
    cats = []

    for line in p.stdout:
        cats.append(line.rstrip('\r\n').split(';')[0])
    p.wait()

    number = len(cats)
    if number < 1:
        grass.fatal(_("No categories found in raster map"))

    # check if DBF driver used, in this case cut to 10 chars col names:
    try:
        fi = grass.vector_db(map=vector)[int(layer)]
    except KeyError:
        grass.fatal(_('There is no table connected to this map. Run v.db.connect or v.db.addtable first.'))
    # we need this for non-DBF driver:
    dbfdriver = fi['driver'] == 'dbf'

    # Find out which table is linked to the vector map on the given layer
    if not fi['table']:
        grass.fatal(_('There is no table connected to this map. Run v.db.connect or v.db.addtable first.'))

    # replaced by user choiche
    #basecols = ['n', 'min', 'max', 'range', 'mean', 'stddev', 'variance', 'cf_var', 'sum']

    # we need at least three chars to distinguish [mea]n from [med]ian
    # so colprefix can't be longer than 6 chars with DBF driver
    if dbfdriver:
        colprefix = colprefix[:6]
        variables_dbf = {}

    # by default perccol variable is used only for "variables" variable
    perccol = "percentile"
    perc = None
    for b in basecols:
        if b.startswith('p'):
            perc = b
    if perc:
        # namespace is limited in DBF but the % value is important
        if dbfdriver:
            perccol = "per" + percentile
        else:
            perccol = "percentile_" + percentile
        percindex = basecols.index(perc)
        basecols[percindex] = perccol

    # dictionary with name of methods and position in "r.univar -gt"  output
    variables = {'number': 2, 'minimum': 4, 'maximum': 5, 'range': 6,
                 'average': 7, 'stddev': 9, 'variance': 10, 'coeff_var': 11,
                 'sum': 12, 'first_quartile': 14, 'median': 15,
                 'third_quartile': 16, perccol: 17}
    # this list is used to set the 'e' flag for r.univar
    extracols = ['first_quartile', 'median', 'third_quartile', perccol]
    addcols = []
    colnames = []
    extstat = ""
    for i in basecols:
        # this check the complete name of out input that should be truncated
        for k in variables.keys():
            if i in k:
                i = k
                break
        if i in extracols:
            extstat = 'e'
        # check if column already present
        currcolumn = ("%s_%s" % (colprefix, i))
        if dbfdriver:
            currcolumn = currcolumn[:10]
            variables_dbf[currcolumn.replace("%s_" % colprefix, '')] = i

        colnames.append(currcolumn)
        if currcolumn in grass.vector_columns(vector, layer).keys():
            if not flags['c']:
                grass.fatal((_("Cannot create column <%s> (already present). ") % currcolumn) +
                             _("Use -c flag to update values in this column."))
        else:
            if i == "n":
                coltype = "INTEGER"
            else:
                coltype = "DOUBLE PRECISION"
            addcols.append(currcolumn + ' ' + coltype)

    if addcols:
        grass.verbose(_("Adding columns '%s'") % addcols)
        try:
            grass.run_command('v.db.addcolumn', map=vector, columns=addcols,
                              layer=layer)
        except CalledModuleError:
            grass.fatal(_("Adding columns failed. Exiting."))

    # calculate statistics:
    grass.message(_("Processing input data (%d categories)...") % number)

    # get rid of any earlier attempts
    grass.try_remove(sqltmp)

    f = file(sqltmp, 'w')

    # do the stats
    p = grass.pipe_command('r.univar', flags='t' + extstat, map=raster,
                           zones=rastertmp, percentile=percentile, sep=';')

    first_line = 1

    f.write("{}\n".format(grass.db_begin_transaction(fi['driver'])))
    for line in p.stdout:
        if first_line:
            first_line = 0
            continue

        vars = line.rstrip('\r\n').split(';')

        f.write("UPDATE %s SET" % fi['table'])
        first_var = 1
        for colname in colnames:
            variable = colname.replace("%s_" % colprefix, '', 1)
            if dbfdriver:
                variable = variables_dbf[variable]
            i = variables[variable]
            value = vars[i]
            # convert nan, +nan, -nan, inf, +inf, -inf, Infinity, +Infinity,
            # -Infinity to NULL
            if value.lower().endswith('nan') or 'inf' in value.lower():
                value = 'NULL'
            if not first_var:
                f.write(" , ")
            else:
                first_var = 0
            f.write(" %s=%s" % (colname, value))

        f.write(" WHERE %s=%s;\n" % (fi['key'], vars[0]))
    f.write("{}\n".format(grass.db_commit_transaction(fi['driver'])))
    p.wait()
    f.close()

    grass.message(_("Updating the database ..."))
    exitcode = 0
    try:
        grass.run_command('db.execute', input=sqltmp,
                          database=fi['database'], driver=fi['driver'])
        grass.verbose((_("Statistics calculated from raster map <{raster}>"
                         " and uploaded to attribute table"
                         " of vector map <{vector}>."
                         ).format(raster=raster, vector=vector)))
    except CalledModuleError:
        grass.warning(_("Failed to upload statistics to attribute table of vector map <%s>.") % vector)
        exitcode = 1

    sys.exit(exitcode)
Exemple #33
0
def main():
    mapname = options["map"]
    layer = options["layer"]
    option = options["option"]
    units = options["units"]
    sort = options["sort"]
    fs = separator(options["separator"])

    nuldev = open(os.devnull, "w")

    if not grass.find_file(mapname, "vector")["file"]:
        grass.fatal(_("Vector map <%s> not found") % mapname)

    if int(layer) in grass.vector_db(mapname):
        colnames = grass.vector_columns(mapname,
                                        layer,
                                        getDict=False,
                                        stderr=nuldev)
        isConnection = True
    else:
        isConnection = False
        colnames = ["cat"]

    if option == "coor":
        extracolnames = ["x", "y", "z"]
    else:
        extracolnames = [option]

    if units == "percent":
        unitsp = "meters"
    elif units:
        unitsp = units
    else:
        unitsp = None

    # NOTE: we suppress -1 cat and 0 cat
    if isConnection:
        f = grass.vector_db(map=mapname)[int(layer)]
        p = grass.pipe_command("v.db.select",
                               flags="e",
                               quiet=True,
                               map=mapname,
                               layer=layer)
        records1 = []
        catcol = -1
        ncols = 0
        for line in p.stdout:
            cols = decode(line).rstrip("\r\n").split("|")
            if catcol == -1:
                ncols = len(cols)
                for i in range(0, ncols):
                    if cols[i] == f["key"]:
                        catcol = i
                        break
                if catcol == -1:
                    grass.fatal(
                        _("There is a table connected to input vector map '%s', but "
                          "there is no key column '%s'.") %
                        (mapname, f["key"]))
                continue
            if cols[catcol] == "-1" or cols[catcol] == "0":
                continue
            records1.append(cols[:catcol] + [int(cols[catcol])] +
                            cols[(catcol + 1):])
        p.wait()
        if p.returncode != 0:
            sys.exit(1)

        records1.sort(key=lambda r: r[catcol])

        if len(records1) == 0:
            try:
                grass.fatal(
                    _("There is a table connected to input vector map '%s', but "
                      "there are no categories present in the key column '%s'. Consider using "
                      "v.to.db to correct this.") % (mapname, f["key"]))
            except KeyError:
                pass

        # fetch the requested attribute sorted by cat:
        p = grass.pipe_command(
            "v.to.db",
            flags="p",
            quiet=True,
            map=mapname,
            option=option,
            layer=layer,
            units=unitsp,
        )
        records2 = []
        for line in p.stdout:
            fields = decode(line).rstrip("\r\n").split("|")
            if fields[0] in ["cat", "-1", "0"]:
                continue
            records2.append([int(fields[0])] + fields[1:])
        p.wait()
        records2.sort()

        # make pre-table
        # len(records1) may not be the same as len(records2) because
        # v.db.select can return attributes that are not linked to features.
        records3 = []
        for r2 in records2:
            rec = list(filter(lambda r1: r1[catcol] == r2[0], records1))
            if len(rec) > 0:
                res = rec[0] + r2[1:]
            elif flags["d"]:
                res = [r2[0]] + [""] * (ncols - 1) + r2[1:]
            else:
                continue
            records3.append(res)
    else:
        catcol = 0
        records1 = []
        p = grass.pipe_command("v.category",
                               inp=mapname,
                               layer=layer,
                               option="print")
        for line in p.stdout:
            field = int(decode(line).rstrip())
            if field > 0:
                records1.append(field)
        p.wait()
        records1.sort()
        records1 = uniq(records1)

        # make pre-table
        p = grass.pipe_command(
            "v.to.db",
            flags="p",
            quiet=True,
            map=mapname,
            option=option,
            layer=layer,
            units=unitsp,
        )
        records3 = []
        for line in p.stdout:
            fields = decode(line).rstrip("\r\n").split("|")
            if fields[0] in ["cat", "-1", "0"]:
                continue
            records3.append([int(fields[0])] + fields[1:])
        p.wait()
        records3.sort()

    # print table header
    if not flags["c"]:
        sys.stdout.write(fs.join(colnames + extracolnames) + "\n")

    # make and print the table:
    numcols = len(colnames) + len(extracolnames)

    # calculate percents if requested
    if units == "percent" and option != "coor":
        # calculate total value
        total = 0
        for r in records3:
            total += float(r[-1])

        # calculate percentages
        records4 = [float(r[-1]) * 100 / total for r in records3]
        if type(records1[0]) == int:
            records3 = [[r1] + [r4] for r1, r4 in zip(records1, records4)]
        else:
            records3 = [r1 + [r4] for r1, r4 in zip(records1, records4)]

    # sort results
    if sort:
        if sort == "asc":
            if option == "coor":
                records3.sort(
                    key=lambda r: (float(r[-3]), float(r[-2]), float(r[-1])))
            else:
                records3.sort(key=lambda r: float(r[-1]))
        else:
            if option == "coor":
                records3.sort(
                    key=lambda r: (float(r[-3]), float(r[-2]), float(r[-1])),
                    reverse=True,
                )
            else:
                records3.sort(key=lambda r: float(r[-1]), reverse=True)

    for r in records3:
        sys.stdout.write(fs.join(map(str, r)) + "\n")
Exemple #34
0
def main(options, flags):

    # Check if running in GRASS
    gisbase = os.getenv("GISBASE")
    if not gisbase:
        gs.fatal(_("$GISBASE not defined"))
        return 0

    # variables
    ipl = options["env"]
    ipl = ipl.split(",")
    raster_exists(ipl)
    ipn = [z.split("@")[0] for z in ipl]
    ipn = [x.lower() for x in ipn]
    out = options["output"]
    if out:
        tmpf0 = out
    else:
        tmpf0 = tmpname("reb0")
    filename = options["file"]
    ref = options["ref"]
    flag_m = flags["m"]
    flag_n = flags["n"]
    flag_o = flags["o"]
    flag_i = flags["i"]
    digits = int(options["digits"])
    digits2 = pow(10, digits)

    # Check if ref map is of type cell and values are limited to 1 and 0
    reftype = gs.raster_info(ref)
    if reftype['datatype'] != "CELL":
        gs.fatal(_("Your reference map must have type CELL (integer)"))
    if reftype['min'] != 0 or reftype['max'] != 1:
        gs.fatal(
            _("The input raster map must be a binary raster,"
              " i.e. it should contain only values 0 and 1 "
              " (now the minimum is %d and maximum is %d)") %
            (reftype['min'], reftype['max']))

    # Text for history in metadata
    opt2 = dict((k, v) for k, v in options.iteritems() if v)
    hist = ' '.join("{!s}={!r}".format(k, v) for (k, v) in opt2.iteritems())
    hist = "r.meb {}".format(hist)
    unused, tmphist = tempfile.mkstemp()
    text_file = open(tmphist, "w")
    text_file.write(hist)
    text_file.close()

    # ------------------------------------------------------------------------
    # Compute MES
    # ------------------------------------------------------------------------

    # Create temporary copy of ref layer
    tmpref0 = tmpname("reb1")
    CLEAN_RAST.append(tmpref0)
    gs.run_command("g.copy", quiet=True, raster=(ref, tmpref0))

    ipi = []
    for j in xrange(len(ipl)):
        # Calculate the frequency distribution
        tmpf1 = tmpname("reb1")
        CLEAN_RAST.append(tmpf1)
        laytype = gs.raster_info(ipl[j])["datatype"]
        if laytype == "CELL":
            gs.run_command("g.copy", quiet=True, raster=(ipl[j], tmpf1))
        else:
            gs.mapcalc("$tmpf1 = int($dignum * $inplay)",
                       tmpf1=tmpf1,
                       inplay=ipl[j],
                       dignum=digits2,
                       quiet=True)
        p = gs.pipe_command("r.stats",
                            quiet=True,
                            flags="cn",
                            input=tmpf1,
                            sort="asc",
                            sep=";")
        stval = {}
        for line in p.stdout:
            [val, count] = line.strip(os.linesep).split(";")
            stval[float(val)] = float(count)
        p.wait()
        sstval = sorted(stval.items(), key=operator.itemgetter(0))
        sstval = np.matrix(sstval)
        a = np.cumsum(np.array(sstval), axis=0)
        b = np.sum(np.array(sstval), axis=0)
        c = a[:, 1] / b[1] * 100

        # Create recode rules
        e1 = np.min(np.array(sstval), axis=0)[0] - 99999
        e2 = np.max(np.array(sstval), axis=0)[0] + 99999
        a1 = np.hstack([(e1), np.array(sstval.T[0])[0, :]])
        a2 = np.hstack([np.array(sstval.T[0])[0, :] - 1, (e2)])
        b1 = np.hstack([(0), c])

        fd2, tmprule = tempfile.mkstemp()
        text_file = open(tmprule, "w")
        for k in np.arange(0, len(b1.T)):
            text_file.write("{}:{}:{}\n".format(int(a1[k]), int(a2[k]), b1[k]))
        text_file.close()

        # Create the recode layer and calculate the IES
        tmpf2 = tmpname("reb2")
        CLEAN_RAST.append(tmpf2)
        gs.run_command("r.recode", input=tmpf1, output=tmpf2, rules=tmprule)

        tmpf3 = tmpname("reb3")
        CLEAN_RAST.append(tmpf3)

        calcc = "{1} = if({0} <= 50, 2 * float({0}), if({0} < 100, " \
                "2 * (100 - float({0}))))".format(tmpf2, tmpf3)
        gs.mapcalc(calcc, quiet=True)
        gs.run_command("g.remove",
                       quiet=True,
                       flags="f",
                       type="raster",
                       name=(tmpf2, tmpf1))
        os.close(fd2)
        os.remove(tmprule)
        ipi.append(tmpf3)

    # ----------------------------------------------------------------------
    # Calculate EB statistics
    # ----------------------------------------------------------------------

    # EB MES
    if flag_m:
        gs.info(_("\nThe EB based on mean ES values:\n"))
        nmn = "{}_MES_mean".format(tmpf0)
        gs.run_command("r.series",
                       quiet=True,
                       output=nmn,
                       input=tuple(ipi),
                       method="average")
        gs.write_command("r.colors",
                         map=nmn,
                         rules="-",
                         stdin=COLORS_MES,
                         quiet=True)
        ebm = EB(simlay=nmn, reflay=tmpref0)
        if not out:
            # Add to list of layers to be removed at completion
            CLEAN_RAST.append(nmn)
        else:
            # Write layer metadata
            gs.run_command("r.support",
                           map=nmn,
                           title="Multivariate environmental similarity (MES)",
                           units="0-100 (relative score",
                           description="MES (compuated as the average of "
                           "the individual similarity layers",
                           loadhistory=tmphist)

    if flag_n:
        gs.info(_("\nThe EB based on median ES values:\n"))
        nmn = "{}_MES_median".format(tmpf0)
        gs.run_command("r.series",
                       quiet=True,
                       output=nmn,
                       input=tuple(ipi),
                       method="median")
        gs.write_command("r.colors",
                         map=nmn,
                         rules="-",
                         stdin=COLORS_MES,
                         quiet=True)
        ebn = EB(simlay=nmn, reflay=tmpref0)
        if not out:
            CLEAN_RAST.append(nmn)
        else:
            # Write layer metadata
            gs.run_command("r.support",
                           map=nmn,
                           title="Multivariate environmental similarity (MES)",
                           units="0-100 (relative score",
                           description="MES (compuated as the median of "
                           "the individual similarity layers",
                           loadhistory=tmphist)

    if flag_o:
        gs.info(_("\nThe EB based on minimum ES values:\n"))
        nmn = "{}_MES_minimum".format(tmpf0)
        gs.run_command("r.series",
                       quiet=True,
                       output=nmn,
                       input=tuple(ipi),
                       method="minimum")
        gs.write_command("r.colors",
                         map=nmn,
                         rules="-",
                         stdin=COLORS_MES,
                         quiet=True)
        ebo = EB(simlay=nmn, reflay=tmpref0)
        if not out:
            CLEAN_RAST.append(nmn)
        else:
            # Write layer metadata
            gs.run_command("r.support",
                           map=nmn,
                           title="Multivariate environmental similarity (MES)",
                           units="0-100 (relative score",
                           description="MES (compuated as the minimum of "
                           "the individual similarity layers",
                           loadhistory=tmphist)

    # EB individual layers
    if flag_i:
        ebi = {}
        for mm in xrange(len(ipi)):
            nmn = "{}_{}".format(tmpf0, ipn[mm])
            if not out:
                CLEAN_RAST.append(nmn)
            gs.run_command("g.rename", quiet=True, raster=(ipi[mm], nmn))
            gs.write_command("r.colors",
                             map=nmn,
                             rules="-",
                             stdin=COLORS_MES,
                             quiet=True)
            gs.info(_("\nThe EB for {}:\n").format(ipn[mm]))
            value = EB(simlay=nmn, reflay=tmpref0)
            ebi[ipn[mm]] = value
            gs.run_command("r.support",
                           map=nmn,
                           title="Environmental similarity (ES) for "
                           "{}".format(ipn[mm]),
                           units="0-100 (relative score",
                           description="Environmental similarity (ES) for "
                           "{}".format(ipn[mm]),
                           loadhistory=tmphist)
    else:
        gs.run_command("g.remove",
                       quiet=True,
                       flags="f",
                       type="raster",
                       name=ipi)

    if filename:
        with open(filename, "wb") as csvfile:
            fieldnames = [
                "variable", "median_region", "median_reference", "mad", "eb"
            ]
            writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
            writer.writeheader()
            if flag_m:
                writer.writerow({
                    "variable": "MES_mean",
                    "median_region": ebm[1],
                    "median_reference": ebm[2],
                    "mad": ebm[0],
                    "eb": ebm[3]
                })
            if flag_n:
                writer.writerow({
                    "variable": "MES_median",
                    "median_region": ebn[1],
                    "median_reference": ebn[2],
                    "mad": ebn[0],
                    "eb": ebn[3]
                })
            if flag_o:
                writer.writerow({
                    "variable": "MES_minimum",
                    "median_region": ebo[1],
                    "median_reference": ebo[2],
                    "mad": ebo[0],
                    "eb": ebo[3]
                })
            if flag_i:
                mykeys = ebi.keys()
                for vari in mykeys:
                    ebj = ebi[vari]
                    writer.writerow({
                        "variable": vari,
                        "median_region": ebj[1],
                        "median_reference": ebj[2],
                        "mad": ebj[0],
                        "eb": ebj[3]
                    })
        gs.info(_("\nThe results are written to {}\n").format(filename))
        gs.info("\n")
Exemple #35
0
def main():
    mapname = options['map']
    option = options['option']
    layer = options['layer']
    units = options['units']

    nuldev = open(os.devnull, 'w')

    if not grass.find_file(mapname, 'vector')['file']:
        grass.fatal(_("Vector map <%s> not found") % mapname)

    if int(layer) in grass.vector_db(mapname):
        colnames = grass.vector_columns(mapname,
                                        layer,
                                        getDict=False,
                                        stderr=nuldev)
        isConnection = True
    else:
        isConnection = False
        colnames = ['cat']

    if option == 'coor':
        extracolnames = ['x', 'y', 'z']
    else:
        extracolnames = [option]

    if units == 'percent':
        unitsp = 'meters'
    elif units:
        unitsp = units
    else:
        unitsp = None

    # NOTE: we suppress -1 cat and 0 cat
    if isConnection:
        f = grass.vector_db(map=mapname)[int(layer)]
        p = grass.pipe_command('v.db.select',
                               quiet=True,
                               map=mapname,
                               layer=layer)
        records1 = []
        catcol = -1
        ncols = 0
        for line in p.stdout:
            cols = decode(line).rstrip('\r\n').split('|')
            if catcol == -1:
                ncols = len(cols)
                for i in range(0, ncols):
                    if cols[i] == f['key']:
                        catcol = i
                        break
                if catcol == -1:
                    grass.fatal(
                        _("There is a table connected to input vector map '%s', but "
                          "there is no key column '%s'.") %
                        (mapname, f['key']))
                continue
            if cols[catcol] == '-1' or cols[catcol] == '0':
                continue
            records1.append(cols[:catcol] + [int(cols[catcol])] +
                            cols[(catcol + 1):])
        p.wait()
        if p.returncode != 0:
            sys.exit(1)

        records1.sort(key=lambda r: r[catcol])

        if len(records1) == 0:
            try:
                grass.fatal(
                    _("There is a table connected to input vector map '%s', but "
                      "there are no categories present in the key column '%s'. Consider using "
                      "v.to.db to correct this.") % (mapname, f['key']))
            except KeyError:
                pass

        # fetch the requested attribute sorted by cat:
        p = grass.pipe_command('v.to.db',
                               flags='p',
                               quiet=True,
                               map=mapname,
                               option=option,
                               layer=layer,
                               units=unitsp)
        records2 = []
        for line in p.stdout:
            fields = decode(line).rstrip('\r\n').split('|')
            if fields[0] in ['cat', '-1', '0']:
                continue
            records2.append([int(fields[0])] + fields[1:])
        p.wait()
        records2.sort()

        # make pre-table
        # len(records1) may not be the same as len(records2) because
        # v.db.select can return attributes that are not linked to features.
        records3 = []
        for r2 in records2:
            rec = list(filter(lambda r1: r1[catcol] == r2[0], records1))
            if len(rec) > 0:
                res = rec[0] + r2[1:]
            elif flags['d']:
                res = [r2[0]] + [''] * (ncols - 1) + r2[1:]
            else:
                continue
            records3.append(res)
    else:
        catcol = 0
        records1 = []
        p = grass.pipe_command('v.category',
                               inp=mapname,
                               layer=layer,
                               option='print')
        for line in p.stdout:
            field = int(decode(line).rstrip())
            if field > 0:
                records1.append(field)
        p.wait()
        records1.sort()
        records1 = uniq(records1)

        # make pre-table
        p = grass.pipe_command('v.to.db',
                               flags='p',
                               quiet=True,
                               map=mapname,
                               option=option,
                               layer=layer,
                               units=unitsp)
        records3 = []
        for line in p.stdout:
            fields = decode(line).rstrip('\r\n').split('|')
            if fields[0] in ['cat', '-1', '0']:
                continue
            records3.append([int(fields[0])] + fields[1:])
        p.wait()
        records3.sort()

    # print table header
    if not flags['c']:
        sys.stdout.write('|'.join(colnames + extracolnames) + '\n')

    # make and print the table:
    numcols = len(colnames) + len(extracolnames)

    # calculate percents if requested
    if units == 'percent' and option != 'coor':
        # calculate total value
        total = 0
        for r in records3:
            total += float(r[-1])

        # calculate percentages
        records4 = [float(r[-1]) * 100 / total for r in records3]
        if type(records1[0]) == int:
            records3 = [[r1] + [r4] for r1, r4 in zip(records1, records4)]
        else:
            records3 = [r1 + [r4] for r1, r4 in zip(records1, records4)]

    # sort results
    if options['sort']:
        if options['sort'] == 'asc':
            if options['option'] == 'coor':
                records3.sort(
                    key=lambda r: (float(r[-3]), float(r[-2]), float(r[-1])))
            else:
                records3.sort(key=lambda r: float(r[-1]))
        else:
            if options['option'] == 'coor':
                records3.sort(key=lambda r:
                              (float(r[-3]), float(r[-2]), float(r[-1])),
                              reverse=True)
            else:
                records3.sort(key=lambda r: float(r[-1]), reverse=True)

    for r in records3:
        sys.stdout.write('|'.join(map(str, r)) + '\n')
Exemple #36
0
def main():

    input = options['input']
    if options['refline']:
        refline_cat = int(options['refline'])
    else:
        refline_cat = None
    nb_vertices = int(options['vertices'])
    if options['range']:
        search_range = float(options['range'])
    else:
        search_range = None
    output = options['output']
    transversals = flags['t']
    median = flags['m']

    global tmp_points_map
    global tmp_centerpoints_map
    global tmp_line_map
    global tmp_cleaned_map
    global tmp_map
    tmp_points_map = 'points_map_tmp_%d' % os.getpid()
    tmp_centerpoints_map = 'centerpoints_map_tmp_%d' % os.getpid()
    tmp_line_map = 'line_map_tmp_%d' % os.getpid()
    tmp_cleaned_map = 'cleaned_map_tmp_%d' % os.getpid()
    tmp_map = 'generaluse_map_tmp_%d' % os.getpid()

    nb_lines = grass.vector_info_topo(input)['lines']

    # Find best reference line and max distance between centerpoints of lines
    segment_input = ''
    categories = grass.pipe_command('v.category',
                                    input=input,
                                    option='print',
                                    quiet=True)
    for category in categories.stdout:
        segment_input += 'P ' + category.strip()
        segment_input += ' ' + category.strip() + ' 50%\n'

    grass.write_command('v.segment',
                        input=input,
                        output=tmp_centerpoints_map,
                        rules='-',
                        stdin=segment_input,
                        quiet=True)

    center_distances = grass.pipe_command('v.distance',
                                          from_=tmp_centerpoints_map,
                                          to=tmp_centerpoints_map,
                                          upload='dist',
                                          flags='pa',
                                          quiet=True)

    cats = []
    mean_dists = []
    count = 0
    distmax = 0
    for center in center_distances.stdout:
        if count < 2:
            count += 1
            continue
        cat = center.strip().split('|')[0]
        distsum = 0
        for x in center.strip().split('|')[1:]:
            distsum += float(x)
        mean_dist = distsum / len(center.strip().split('|')[1:])
        cats.append(cat)
        mean_dists.append(mean_dist)

    if transversals and not search_range:
        search_range = sum(mean_dists) / len(mean_dists)
        grass.message(_("Calculated search range:  %.5f." % search_range))

    if not refline_cat:
        refline_cat = sorted(zip(cats, mean_dists),
                             key=lambda tup: tup[1])[0][0]

        grass.message(
            _("Category number of chosen reference line: %s." % refline_cat))

    # Use transversals algorithm
    if transversals:

        # Break any intersections in the original lines so that
        # they do not interfere further on
        grass.run_command('v.clean',
                          input=input,
                          output=tmp_cleaned_map,
                          tool='break',
                          quiet=True)

        xmean = []
        ymean = []
        xmedian = []
        ymedian = []
        step = 100.0 / nb_vertices

        os.environ['GRASS_VERBOSE'] = '-1'

        for vertice in range(0, nb_vertices + 1):
            # v.segment sometimes cannot find points when
            # using 0% or 100% offset
            length_offset = step * vertice
            if length_offset < 0.00001:
                length_offset = 0.00001
            if length_offset > 99.99999:
                length_offset = 99.9999
            # Create endpoints of transversal
            segment_input = 'P 1 %s %.5f%% %f\n' % (refline_cat, length_offset,
                                                    search_range)
            segment_input += 'P 2 %s %.5f%% %f\n' % (
                refline_cat, length_offset, -search_range)
            grass.write_command('v.segment',
                                input=input,
                                output=tmp_points_map,
                                stdin=segment_input,
                                overwrite=True)

            # Create transversal
            grass.write_command('v.net',
                                points=tmp_points_map,
                                output=tmp_line_map,
                                operation='arcs',
                                file='-',
                                stdin='99999 1 2',
                                overwrite=True)

            # Patch transversal onto cleaned input lines
            maps = tmp_cleaned_map + ',' + tmp_line_map
            grass.run_command('v.patch',
                              input=maps,
                              out=tmp_map,
                              overwrite=True)

            # Find intersections
            grass.run_command('v.clean',
                              input=tmp_map,
                              out=tmp_line_map,
                              tool='break',
                              error=tmp_points_map,
                              overwrite=True)

            # Add categories to intersection points
            grass.run_command('v.category',
                              input=tmp_points_map,
                              out=tmp_map,
                              op='add',
                              overwrite=True)

            # Get coordinates of points
            coords = grass.pipe_command('v.to.db',
                                        map=tmp_map,
                                        op='coor',
                                        flags='p')

            count = 0
            x = []
            y = []
            for coord in coords.stdout:
                x.append(float(coord.strip().split('|')[1]))
                y.append(float(coord.strip().split('|')[2]))

            # Calculate mean and median for this transversal
            if len(x) > 0:
                xmean.append(sum(x) / len(x))
                ymean.append(sum(y) / len(y))

                x.sort()
                y.sort()

                xmedian.append((x[(len(x) - 1) / 2] + x[(len(x)) / 2]) / 2)
                ymedian.append((y[(len(y) - 1) / 2] + y[(len(y)) / 2]) / 2)

        del os.environ['GRASS_VERBOSE']

    # Use closest point algorithm
    else:

        # Get reference line calculate its length
        grass.run_command('v.extract',
                          input=input,
                          output=tmp_line_map,
                          cats=refline_cat,
                          quiet=True)

        os.environ['GRASS_VERBOSE'] = '0'
        lpipe = grass.pipe_command('v.to.db',
                                   map=tmp_line_map,
                                   op='length',
                                   flags='p')
        del os.environ['GRASS_VERBOSE']

        for l in lpipe.stdout:
            linelength = float(l.strip().split('|')[1])

        step = linelength / nb_vertices

        # Create reference points for vertice calculation
        grass.run_command('v.to.points',
                          input=tmp_line_map,
                          output=tmp_points_map,
                          dmax=step,
                          quiet=True)

        nb_points = grass.vector_info_topo(tmp_points_map)['points']

        cat = []
        x = []
        y = []

        # Get coordinates of closest points on all input lines
        if search_range:
            points = grass.pipe_command('v.distance',
                                        from_=tmp_points_map,
                                        from_layer=2,
                                        to=input,
                                        upload='to_x,to_y',
                                        dmax=search_range,
                                        flags='pa',
                                        quiet=True)
        else:
            points = grass.pipe_command('v.distance',
                                        from_=tmp_points_map,
                                        from_layer=2,
                                        to=input,
                                        upload='to_x,to_y',
                                        flags='pa',
                                        quiet=True)

        firstline = True
        for point in points.stdout:
            if firstline:
                firstline = False
                continue
            cat.append((int(point.strip().split('|')[0])))
            x.append(float(point.strip().split('|')[2]))
            y.append(float(point.strip().split('|')[3]))

        # Calculate mean coordinates
        xsum = [0] * nb_points
        ysum = [0] * nb_points
        linecount = [0] * nb_points

        for i in range(len(cat)):
            index = cat[i] - 1
            linecount[index] += 1
            xsum[index] = xsum[index] + x[i]
            ysum[index] = ysum[index] + y[i]

        xmean = [0] * nb_points
        ymean = [0] * nb_points

        for c in range(0, nb_points):
            xmean[c] = xsum[c] / linecount[c]
            ymean[c] = ysum[c] / linecount[c]

        # Calculate the median

        xmedian = [0] * nb_points
        ymedian = [0] * nb_points

        for c in range(0, nb_points):
            xtemp = []
            ytemp = []
            for i in range(len(cat)):
                if cat[i] == c + 1:
                    xtemp.append(x[i])
                    ytemp.append(y[i])
            xtemp.sort()
            ytemp.sort()
            xmedian[c] = (xtemp[(len(xtemp) - 1) / 2] +
                          xtemp[(len(xtemp)) / 2]) / 2
            ymedian[c] = (ytemp[(len(ytemp) - 1) / 2] +
                          ytemp[(len(ytemp)) / 2]) / 2

    # Create new line and write to file
    if median and nb_lines > 2:
        line = geo.Line(zip(xmedian, ymedian))
    else:
        if median and nb_lines <= 2:
            grass.message(
                _("More than 2 lines necesary for median, using mean."))
        line = geo.Line(zip(xmean, ymean))

    new = VectorTopo(output)
    new.open('w')

    new.write(line)
    new.close()
Exemple #37
0
 def __unicode__(self):
     return grass.pipe_command("g.region", flags="p").communicate()[0]
def main():
    # split input images
    all_images = options['input']
    images = all_images.split(',')
    # number of images
    n_images = len(images)
    # database path
    dbopt = options['database']
    # output suffix
    suffix = options['suffix']
    # output mosaic map
    mosaic = options['output']
    output_names = []
    # name for average table
    table_ave = "t%s_average" % suffix
    # increment of one the maximum value for a correct use of range function
    max_value = int(options['max']) + 1
    # if the db path is the default one
    if dbopt.find('$GISDBASE/$LOCATION_NAME/$MAPSET') == 0:
        dbopt_split = dbopt.split('/')[-1]
        env = grass.gisenv()
        path = os.path.join(env['GISDBASE'], env['LOCATION_NAME'],
                            env['MAPSET'])
        dbpath = os.path.join(path, dbopt_split)
    else:
        if os.access(os.path.dirname(dbopt), os.W_OK):
            path = os.path.dirname(dbopt)
            dbpath = dbopt
        else:
            grass.fatal(
                _("Folder to write database files does not" +
                  " exist or is not writeable"))
    # connect to the db
    db = sqlite3.connect(dbpath)
    curs = db.cursor()
    grass.message(_("Calculating Cumulative Distribution Functions ..."))

    # number of pixels per value, summarized for all images
    numPixelValue = list(range(0, max_value))
    for n in range(0, max_value):
        numPixelValue[n] = 0

    # cumulative histogram for each value and each image
    cumulHistoValue = list(range(0, max_value))

    # set up temp region only once
    grass.use_temp_region()

    # for each image
    for i in images:
        iname = i.split('@')[0]
        # drop table if exist
        query_drop = "DROP TABLE if exists \"t%s\"" % iname
        curs.execute(query_drop)
        # create table
        query_create = "CREATE TABLE \"t%s\" (grey_value integer,pixel_frequency " % iname
        query_create += "integer, cumulative_histogram integer, cdf real)"
        curs.execute(query_create)
        index_create = "CREATE UNIQUE INDEX \"t%s_grey_value\" ON \"t%s\" (grey_value) " % (
            iname, iname)
        curs.execute(index_create)
        # set the region on the raster
        grass.run_command('g.region', raster=i)
        # calculate statistics
        stats_out = grass.pipe_command('r.stats',
                                       flags='cin',
                                       input=i,
                                       separator=':')
        stats = stats_out.communicate()[0].decode('utf-8').split('\n')[:-1]
        stats_dict = dict(s.split(':', 1) for s in stats)
        cdf = 0
        curs.execute("BEGIN")
        # for each number in the range
        for n in range(0, max_value):
            # try to insert the values otherwise insert 0

            try:
                val = int(stats_dict[str(n)])
                cdf += val
                numPixelValue[n] += val
                insert = "INSERT INTO \"t%s\" VALUES (%i, %i, %i, 0.000000)" % (
                    iname, n, val, cdf)
                curs.execute(insert)
            except:
                insert = "INSERT INTO \"t%s\" VALUES (%i, 0, %i, 0.000000)" % (
                    iname, n, cdf)
                curs.execute(insert)
            # save cumulative_histogram for the second loop
            cumulHistoValue[n] = cdf
        curs.execute("COMMIT")
        db.commit()
        # number of pixel is the cdf value
        numPixel = cdf
        # for each number in the range
        # cdf is updated using the number of non-null pixels for the current image
        curs.execute("BEGIN")
        for n in range(0, max_value):
            # select value for cumulative_histogram for the range number
            """
            select_ch = "SELECT cumulative_histogram FROM \"t%s\" WHERE " % iname
            select_ch += "(grey_value=%i)" % n
            result = curs.execute(select_ch)
            val = result.fetchone()[0]
            """
            val = cumulHistoValue[n]
            # update cdf with new value
            if val != 0 and numPixel != 0:
                update_cdf = round(float(val) / float(numPixel), 6)
                update_cdf = "UPDATE \"t%s\" SET cdf=%s WHERE (grey_value=%i)" % (
                    iname, update_cdf, n)
                curs.execute(update_cdf)

        curs.execute("COMMIT")
        db.commit()
    db.commit()
    pixelTot = 0

    # get total number of pixels divided by number of images
    # for each number in the range
    for n in range(0, max_value):
        """
        numPixel = 0
        # for each image
        for i in images:
            iname = i.split('@')[0]
            pixel_freq = "SELECT pixel_frequency FROM \"t%s\" WHERE (grey_value=%i)" % (
                                                                iname, n)
            result = curs.execute(pixel_freq)
            val = result.fetchone()[0]
            numPixel += val
        """
        # calculate number of pixel divide by number of images
        div = (int(numPixelValue[n] / n_images))
        pixelTot += div

    # drop average table
    query_drop = "DROP TABLE if exists %s" % table_ave
    curs.execute(query_drop)
    # create average table
    query_create = "CREATE TABLE %s (grey_value integer,average " % table_ave
    query_create += "integer, cumulative_histogram integer, cdf real)"
    curs.execute(query_create)
    index_create = "CREATE UNIQUE INDEX \"%s_grey_value\" ON \"%s\" (grey_value) " % (
        table_ave, table_ave)
    curs.execute(index_create)
    cHist = 0
    # for each number in the range
    curs.execute("BEGIN")
    for n in range(0, max_value):
        tot = 0
        """
        # for each image
        for i in images:
            iname = i.split('@')[0]
            # select pixel frequency
            pixel_freq = "SELECT pixel_frequency FROM \"t%s\" WHERE (grey_value=%i)" % (
                                                            iname, n)
            result = curs.execute(pixel_freq)
            val = result.fetchone()[0]
            tot += val
        """
        tot = numPixelValue[n]
        # calculate new value of pixel_frequency
        average = (tot / n_images)
        cHist = cHist + int(average)
        # insert new values into average table
        if cHist != 0 and pixelTot != 0:
            cdf = float(cHist) / float(pixelTot)
            insert = "INSERT INTO %s VALUES (%i, %i, %i, %s)" % (
                table_ave, n, int(average), cHist, cdf)
            curs.execute(insert)
    curs.execute("COMMIT")
    db.commit()

    # for each image
    grass.message(_("Reclassifying bands based on average histogram..."))
    for i in images:
        iname = i.split('@')[0]
        grass.run_command('g.region', raster=i)
        # write average rules file
        outfile = open(grass.tempfile(), 'w')
        new_grey = 0
        for n in range(0, max_value):
            select_newgrey = "SELECT b.grey_value FROM \"t%s\" as a, " % iname
            select_newgrey += "%s as b WHERE a.grey_value=%i " % (table_ave, n) \
                + "ORDER BY abs(a.cdf-b.cdf) LIMIT 1"
            # write line with old and new value
            try:
                result_new = curs.execute(select_newgrey)
                new_grey = result_new.fetchone()[0]
                out_line = "%d = %d\n" % (n, new_grey)
                outfile.write(out_line)
            except:
                out_line = "%d = %d\n" % (n, new_grey)
                outfile.write(out_line)

        outfile.close()
        outname = '%s.%s' % (iname, suffix)
        # check if a output map already exists
        result = grass.core.find_file(outname, element='cell')
        if result['fullname'] and grass.overwrite():
            grass.run_command('g.remove',
                              flags='f',
                              type='raster',
                              name=outname)
            grass.run_command('r.reclass',
                              input=i,
                              out=outname,
                              rules=outfile.name)
        elif result['fullname'] and not grass.overwrite():
            grass.warning(
                _("Raster map %s already exists and will not be overwritten" %
                  i))
        else:
            grass.run_command('r.reclass',
                              input=i,
                              out=outname,
                              rules=outfile.name)
        output_names.append(outname)
        # remove the rules file
        grass.try_remove(outfile.name)
        # write cmd history:
        grass.raster_history(outname)
    db.commit()
    db.close()
    if mosaic:
        grass.message(_("Processing mosaic <%s>..." % mosaic))
        grass.run_command('g.region', raster=all_images)
        grass.run_command('r.patch', input=output_names, output=mosaic)
Exemple #39
0
def main():
    res = options['res']
    poly1 = options['map']
    if "@" in poly1:
        poly1 = poly1.split("@")[0]
    poly2 = options['query_map']
    qcol = options['query_column']
    if not res:
        cur_region = grass.region()
        res = cur_region['nsres']
    
    grass.run_command('g.region', res = res, quiet = True)
    grass.run_command('v.to.rast', type_ = 'area',
                      input_ = poly2, output = 'raster_tmp',
                      use = 'attr', attribute_column = 'cat',
                      label_column = qcol,
                      quiet = True)

    p = grass.pipe_command('r.category', map = 'raster_tmp',
                           separator = '|', quiet = True)
    cats = []
    labels = []
    for line in p.stdout:
        cats.append(line.rstrip('\r\n').split('|')[0])
        labels.append(line.rstrip('\r\n').split('|')[1])
    p.wait()

    query_dict = dict(zip(cats,labels))

    grass.run_command('v.extract', input_ = poly1,
                      output = 'vector_tmp1',
                      type_ = 'centroid',
                      overwrite = True, quiet = True)
    grass.run_command('v.category', input_ = poly1,
                      output = 'vector_tmp2',
                      option = 'add', flags = 't',
                      type_ = 'boundary',
                      overwrite = True)
    # grass.run_command('v.extract', input_ = 'vector_tmp2',
    #                   output = 'vector_tmp3',
    #                   type_ = 'boundary',
    #                   overwrite = True)
    # grass.run_command('v.edit', map_ = 'vector_tmp3',
    #                   tool = 'delete',
    #                   type_ = 'centroid',
    #                   ids = 0-99999999,
    #                   overwrite = True)
    # grass.run_command('v.category', input_ = 'vector_tmp3',
    #                   output = 'vector_tmp4',
    #                   option = 'del',
    #                   type_ = 'boundary',
    #                   overwrite = True)    
    grass.run_command('v.db.addcolumn', map_ = 'vector_tmp1',
                      column = 'rast_cat int', quiet = True)
    grass.run_command('v.db.addcolumn', map_ = 'vector_tmp1',
                      column = qcol, quiet = True)
    grass.run_command('v.what.rast', map_ = 'vector_tmp1',
                      raster = 'raster_tmp',
                      column = 'rast_cat',
                      type_ = 'centroid',
                      overwrite = True, quiet = True)    

    for key,value in query_dict.items():
        grass.run_command('v.db.update', map_ = 'vector_tmp1',
                          col = qcol, value = value,
                          where = "rast_cat = %s" % key,
                          quiet = True)

    grass.run_command('v.db.dropcolumn', map_ = 'vector_tmp1',
                      column = 'rast_cat', quiet = True)

    grass.run_command('v.edit', map_ = 'vector_tmp1',
                      tool = 'copy', bgmap = 'vector_tmp2',
                      type_ = 'boundary', cats = 0-99999999)

    sys.exit(0)
    
    grass.run_command('g.rename', vector = ('vector_tmp1', poly1),
                      overwrite = True, quiet = True)
def main():
    """Do the main work"""

    alias_output = options["alias_output"]

    bgr_mask = options["bgr_mask"]

    null_value = options["null_value"]

    bgr_output = options["bgr_output"]
    species_output = options["species_output"]

    alias, parameters = parse_bgr_input(
        options["alias_input"], options["env_maps"], options["alias_names"]
    )

    species_dict = parse_species_input(
        options["species_masks"], options["species_names"]
    )

    # Check if a mask file allready exists
    if RasterRow("MASK", Mapset().name).exist():
        gscript.verbose(
            _("A mask allready exists. Renaming existing mask to old_MASK...")
        )
        gscript.run_command(
            "g.rename", rast="MASK,{}_MASK".format(TMP_NAME), quiet=True
        )

    # Build parameter header if necessary
    header = ",".join(alias)

    # Write alias output if requested
    if alias_output:
        with open(alias_output, "w") as alias_out:
            for idx, name in enumerate(alias):
                alias_out.write("{},{}\n".format(name, parameters[idx]))

    # Check if specie output is requested and produce it
    if species_output and species_dict:
        # Write header to species output SWD file
        species_header = "species,X,Y,{}\n".format(header)

        with open(species_output, "w") as sp_out:
            sp_out.write(species_header)

        # Parse species input variables
        for species in species_dict:

            species_map = species_dict[species]
            # Zoom region to match specie map if requested
            if flags["z"]:
                gscript.verbose(
                    _("Zooming region to species {} temporarily.".format(species))
                )
                gscript.use_temp_region()
                gscript.run_command(
                    "g.region", align="@".join(species_map), zoom="@".join(species_map)
                )
            #
            # Apply specie mask
            gscript.run_command(
                "r.mask", raster="@".join(species_map), overwrite=True, quiet=True
            )

            # Export data using r.stats
            gscript.verbose(_("Producing output for species {}".format(species)))
            stats = gscript.pipe_command(
                "r.stats",
                flags="1gN",
                verbose=True,
                input=",".join(parameters),
                separator=",",
                null_value=null_value,
            )

            with open(species_output, "a") as sp_out:
                for row in stats.stdout:
                    sp_out.write("{},{}".format(species, gscript.decode(row)))

            # Redo zoom region to match specie map if it had been requested
            if flags["z"]:
                gscript.del_temp_region()
            # Remove mask
            gscript.run_command("r.mask", flags="r", quiet=True)

    # Write header to background output SWD file
    bgr_header = "bgr,X,Y,{}\n".format(",".join(alias))

    with open(bgr_output, "w") as bgr_out:
        bgr_out.write(bgr_header)

    # Process map data for background
    # Check if a mask file allready exists
    if bgr_mask:
        gscript.verbose(
            _("Using map {} as mask for the background landscape...".format(bgr_mask))
        )
        # Apply mask
        gscript.run_command("r.mask", raster=bgr_mask, overwrite=True, quiet=True)
    #
    # Export data using r.stats
    gscript.verbose(_("Producing output for background landscape"))
    stats = gscript.pipe_command(
        "r.stats",
        flags="1gN",
        input=",".join(parameters),
        separator=",",
        null_value=null_value,
    )

    with open(bgr_output, "a") as bgr_out:
        for row in stats.stdout:
            bgr_out.write("bgr,{}".format(gscript.decode(row)))

    cleanup()
def output_xsections(xsects, outfile, elev, res, river):
	"""
	Create the cross section profiles by first making a points vector from the cross sections
	loop thru the section_ids and use v.out.ascii to get the points for each cross section.
	Feed these points into r.profile to get lists of the coords and elevation at each spot along the xsection,
	and output these to the CROSS-SECTION paragraph
	"""

	# Prepare tmp vector maps to hold the points from the cross sections
	proc=os.getpid()
	xsect_pts="tmp_xsect_pts_"+str(proc)
	#xsect_pts2="tmp_xsect_pts2_"+str(proc)
	# v.to.points returns all points on the same cross section with the same cat value
	grass.run_command('v.to.points', input=xsects, output=xsect_pts, use="vertex", quiet=True)
	outfile.write("\n")
	outfile.write("BEGIN CROSS-SECTIONS:\n")
	
	# Get the list of station ids with the reaches
	# Layer 1 contains one cat for all points on the same xsect line, 
	# so v.db.select returns one row for each xsect line (not for each point on the line)
	st=grass.pipe_command('v.db.select', map=xsect_pts, layer=1, columns="reach,station_id", flags="c", quiet=True)
	station_ids=[]
	for line in st.stdout:	
		station = line.rstrip('\n').split("|")
		r,s = station[0], station[1]
		station_ids.append([r,s])

	st.stdout.close()
	st.wait()
	
	# Now loop thru those stations to create the CUTLINE and SURFACE section
	for i in range(len(station_ids)):
		station_id = station_ids[i][1].strip('\n')
		reach = station_ids[i][0].rstrip('\n')
		process_msg="Processing reach: "+reach+" at station id: "+station_id
		grass.message(process_msg)
		outfile.write(" CROSS-SECTION:\n")
		outfile.write("   STREAM ID: %s\n" % river)
		outfile.write("   REACH ID: %s\n" % reach)
		outfile.write("   STATION: %s\n" % station_id)
			
		# get point coords from this reach/station and print out CUTLINE: section
		# Save this output also for next SURFACE: section
		station_cond="station_id="+station_id
		p=grass.pipe_command('v.out.ascii', input=xsect_pts, columns="reach,station_id", 
			where=station_cond ,separator=",", layer=1, quiet=True)
		station_pts=[]
		for line in p.stdout:
			st = line.rstrip('\n').split(',')
			station_pts.append(st)

		p.stdout.close()
		p.wait()

		outfile.write("   CUTLINE:\n")
		for j in range(len(station_pts)):
			x,y = station_pts[j][0], station_pts[j][1]
			outfile.write("	 "+x+","+y+"\n")  

		# Now run the points thru r.profile, and get the elevations
		# and print elevations to SURFACE LINE: section
		outfile.write("   SURFACE LINE:\n")
		profile_pts=[]
		for k in range(len(station_pts)):
			x,y = station_pts[k][0], station_pts[k][1]
			profile_pts.append([x,y])
			
		pp=grass.pipe_command('r.profile', input=elev, coordinates=profile_pts, resolution=res, flags="g", quiet=True)
		for line in pp.stdout:
			l=line.rstrip('\n').split(" ")
			# The r.profile output has x,y in first two columns and elev in 4th column
			outfile.write("	 "+l[0]+","+l[1]+","+l[3]+"\n")
		pp.stdout.close()
		pp.wait()
		
		# CLose this CROSS-SECTION paragraph
		outfile.write(" END:\n\n")

	outfile.write("END CROSS-SECTIONS:\n\n")

	# remove temp points file
	grass.message("Removing temp vector: %s" % (xsect_pts))
	grass.run_command('g.remove', type='vector', name=xsect_pts, quiet=True, flags="f")
Exemple #42
0
def reclass(inf, outf, lim, clump, diag, les):
    infile = inf
    outfile = outf
    lesser = les
    limit = lim
    clumped = clump
    diagonal = diag

    s = grass.read_command("g.region", flags='p')
    kv = grass.parse_key_val(s, sep=':')
    s = kv['projection'].strip().split()
    if s == '0':
        grass.fatal(_("xy-locations are not supported"))
        grass.fatal(_("Need projected data with grids in meters"))

    if not grass.find_file(infile)['name']:
        grass.fatal(_("Raster map <%s> not found") % infile)

    if clumped and diagonal:
        grass.fatal(_("flags c and d are mutually exclusive"))

    if clumped:
        clumpfile = infile
    else:
        clumpfile = "%s.clump.%s" % (infile.split('@')[0], outfile)
        TMPRAST.append(clumpfile)

        if not grass.overwrite():
            if grass.find_file(clumpfile)['name']:
                grass.fatal(_("Temporary raster map <%s> exists") % clumpfile)
        if diagonal:
            grass.message(_("Generating a clumped raster file including "
                            "diagonal neighbors..."))
            grass.run_command('r.clump', flags='d', input=infile,
                              output=clumpfile)
        else:
            grass.message(_("Generating a clumped raster file ..."))
            grass.run_command('r.clump', input=infile, output=clumpfile)

    if lesser:
        grass.message(_("Generating a reclass map with area size less than "
                        "or equal to %f hectares...") % limit)
    else:
        grass.message(_("Generating a reclass map with area size greater "
                        "than or equal to %f hectares...") % limit)

    recfile = outfile + '.recl'
    TMPRAST.append(recfile)

    sflags = 'aln'
    if grass.raster_info(infile)['datatype'] in ('FCELL', 'DCELL'):
        sflags += 'i'
    p1 = grass.pipe_command('r.stats', flags=sflags, input=(clumpfile, infile),
                            sep=';')
    p2 = grass.feed_command('r.reclass', input=clumpfile, output=recfile,
                            rules='-')
    rules = ''
    for line in p1.stdout:
        f = line.rstrip(os.linesep).split(';')
        if len(f) < 5:
            continue
        hectares = float(f[4]) * 0.0001
        if lesser:
            test = hectares <= limit
        else:
            test = hectares >= limit
        if test:
            rules += "%s = %s %s\n" % (f[0], f[2], f[3])
    if rules:
        p2.stdin.write(rules)
    p1.wait()
    p2.stdin.close()
    p2.wait()
    if p2.returncode != 0:
        if lesser:
            grass.fatal(_("No areas of size less than or equal to %f "
                          "hectares found.") % limit)
        else:
            grass.fatal(_("No areas of size greater than or equal to %f "
                          "hectares found.") % limit)
    grass.mapcalc("$outfile = $recfile", outfile=outfile, recfile=recfile)
Exemple #43
0
def matchhist(original, target, matched):
    # pan/intensity histogram matching using numpy arrays
    grass.message(_("Histogram matching..."))

    # input images
    original = original.split('@')[0]
    target = target.split('@')[0]
    images = [original, target]

    # create a dictionary to hold arrays for each image
    arrays = {}

    for i in images:
        # calculate number of cells for each grey value for for each image
        stats_out = grass.pipe_command('r.stats', flags='cin', input=i,
                                       sep=':')
        stats = stats_out.communicate()[0].split('\n')[:-1]
        stats_dict = dict(s.split(':', 1) for s in stats)
        total_cells = 0  # total non-null cells
        for j in stats_dict:
            stats_dict[j] = int(stats_dict[j])
            if j != '*':
                total_cells += stats_dict[j]

        if total_cells < 1:
            grass.fatal(_("Input has no data. Check region settings."))

        # Make a 2x256 structured array for each image with a
        #   cumulative distribution function (CDF) for each grey value.
        #   Grey value is the integer (i4) and cdf is float (f4).

        arrays[i] = np.zeros((256, ), dtype=('i4,f4'))
        cum_cells = 0  # cumulative total of cells for sum of current and all lower grey values

        for n in range(0, 256):
            if str(n) in stats_dict:
                num_cells = stats_dict[str(n)]
            else:
                num_cells = 0

            cum_cells += num_cells

            # cdf is the the number of cells at or below a given grey value
            #   divided by the total number of cells
            cdf = float(cum_cells) / float(total_cells)

            # insert values into array
            arrays[i][n] = (n, cdf)

    # open file for reclass rules
    outfile = open(grass.tempfile(), 'w')

    for i in arrays[original]:
        # for each grey value and corresponding cdf value in original, find the
        #   cdf value in target that is closest to the target cdf value
        difference_list = []
        for j in arrays[target]:
            # make a list of the difference between each original cdf value and
            #   the target cdf value
            difference_list.append(abs(i[1] - j[1]))

        # get the smallest difference in the list
        min_difference = min(difference_list)

        for j in arrays[target]:
            # find the grey value in target that correspondes to the cdf
            #   closest to the original cdf
            if j[1] == i[1] + min_difference or j[1] == i[1] - min_difference:
                # build a reclass rules file from the original grey value and
                #   corresponding grey value from target
                out_line = "%d = %d\n" % (i[0], j[0])
                outfile.write(out_line)
                break

    outfile.close()

    # create reclass of target from reclass rules file
    result = grass.core.find_file(matched, element='cell')
    if result['fullname']:
        grass.run_command('g.remove', flags='f', quiet=True, type='raster',
                          name=matched)
        grass.run_command('r.reclass', input=original, out=matched,
                          rules=outfile.name)
    else:
        grass.run_command('r.reclass', input=original, out=matched,
                          rules=outfile.name)

    # Cleanup
    # remove the rules file
    grass.try_remove(outfile.name)

    # return reclass of target with histogram that matches original
    return matched
def main():
    infile = options['input']
    lesser = options['lesser']
    greater = options['greater']
    outfile = options['output']

    s = grass.read_command("g.region", flags = 'p')
    kv = grass.parse_key_val(s, sep = ':')
    s = kv['projection'].strip().split()
    if s == '0':
	grass.fatal(_("xy-locations are not supported"))
	grass.fatal(_("Need projected data with grids in meters"))

    if not lesser and not greater:
	grass.fatal(_("You have to specify either lesser= or greater="))
    if lesser and greater:
	grass.fatal(_("lesser= and greater= are mutually exclusive"))
    if lesser:
	limit = float(lesser)
    if greater:
	limit = float(greater)

    if not grass.find_file(infile)['name']:
	grass.fatal(_("Raster map <%s> not found") % infile)

    clumpfile = "%s.clump.%s" % (infile.split('@')[0], outfile)

    if not grass.overwrite():
	if grass.find_file(clumpfile)['name']:
	    grass.fatal(_("Temporary raster map <%s> exists") % clumpfile)

    grass.message(_("Generating a clumped raster file ..."))
    grass.run_command('r.clump', input = infile, output = clumpfile)

    if lesser:
	grass.message(_("Generating a reclass map with area size less than or equal to %f hectares...") % limit)
    else:
	grass.message(_("Generating a reclass map with area size greater than or equal to %f hectares...") % limit)

    recfile = outfile + '.recl'

    p1 = grass.pipe_command('r.stats', flags = 'aln', input = (clumpfile, infile), fs = '|')
    p2 = grass.feed_command('r.reclass', input = clumpfile, output = recfile, rules = '-')
    for line in p1.stdout:
	f = line.rstrip('\r\n').split('|')
	if len(f) < 5:
	    continue
	hectares = float(f[4]) * 0.0001
	if lesser:
	    test = hectares <= limit
	else:
	    test = hectares >= limit
	if test:
	    p2.stdin.write("%s = %s %s\n" % (f[0], f[2], f[3]))
    p1.wait()
    p2.stdin.close()
    p2.wait()

    grass.message(_("Generating output raster map <%s>...") % outfile)

    grass.mapcalc("$outfile = $recfile", outfile = outfile, recfile = recfile)
    grass.run_command('g.remove', rast = [recfile, clumpfile], quiet = True)
Exemple #45
0
def main():
    global tmp, sqltmp, tmpname, nuldev, vector, mask_found, rastertmp
    mask_found = False
    rastertmp = False
    #### setup temporary files
    tmp = grass.tempfile()
    sqltmp = tmp + ".sql"
    # we need a random name
    tmpname = grass.basename(tmp)

    nuldev = file(os.devnull, 'w')

    raster = options['raster']
    colprefix = options['column_prefix']
    vector = options['vector']
    layer = options['layer']
    percentile = options['percentile']

    ### setup enviro vars ###
    env = grass.gisenv()
    mapset = env['MAPSET']

    vs = vector.split('@')
    if len(vs) > 1:
	vect_mapset = vs[1]
    else:
	vect_mapset = mapset

    # does map exist in CURRENT mapset?
    if vect_mapset != mapset or not grass.find_file(vector, 'vector', mapset)['file']:
	grass.fatal(_("Vector map <%s> not found in current mapset") % vector)

    vector = vs[0]

    rastertmp = "%s_%s" % (vector, tmpname)

    # check the input raster map
    if not grass.find_file(raster, 'cell')['file']:
	grass.fatal(_("Raster map <%s> not found") % raster)

    # check presence of raster MASK, put it aside
    mask_found = bool(grass.find_file('MASK', 'cell')['file'])
    if mask_found:
	grass.message(_("Raster MASK found, temporarily disabled"))
	grass.run_command('g.rename', rast = ('MASK', tmpname + "_origmask"), quiet = True)

    # save current settings:
    grass.use_temp_region()

    # Temporarily aligning region resolution to $RASTER resolution
    # keep boundary settings
    grass.run_command('g.region', align = raster)

    # prepare raster MASK
    if grass.run_command('v.to.rast', input = vector, output = rastertmp,
			 use = 'cat', quiet = True) != 0:
	grass.fatal(_("An error occurred while converting vector to raster"))

    # dump cats to file to avoid "too many argument" problem:
    p = grass.pipe_command('r.category', map = rastertmp, fs = ';', quiet = True)
    cats = []
    for line in p.stdout:
	cats.append(line.rstrip('\r\n').split(';')[0])
    p.wait()

    number = len(cats)
    if number < 1:
	grass.fatal(_("No categories found in raster map"))

    # check if DBF driver used, in this case cut to 10 chars col names:
    try:
        fi = grass.vector_db(map = vector)[int(layer)]
    except KeyError:
	grass.fatal(_('There is no table connected to this map. Run v.db.connect or v.db.addtable first.'))
    # we need this for non-DBF driver:
    dbfdriver = fi['driver'] == 'dbf'

    # Find out which table is linked to the vector map on the given layer
    if not fi['table']:
	grass.fatal(_('There is no table connected to this map. Run v.db.connect or v.db.addtable first.'))

    basecols = ['n', 'min', 'max', 'range', 'mean', 'stddev', 'variance', 'cf_var', 'sum']

    # we need at least three chars to distinguish [mea]n from [med]ian
    # so colprefix can't be longer than 6 chars with DBF driver
    if dbfdriver:
	colprefix = colprefix[:6]

    # do extended stats?
    if flags['e']:
	# namespace is limited in DBF but the % value is important
	if dbfdriver:
	    perccol = "per" + percentile
	else:
	    perccol = "percentile_" + percentile
	extracols = ['first_quartile', 'median', 'third_quartile'] + [perccol]
    else:
	extracols = []

    addcols = []
    for i in basecols + extracols:
	# check if column already present
	currcolumn = ("%s_%s" % (colprefix, i))
	if dbfdriver:
	    currcolumn = currcolumn[:10]

	if currcolumn in grass.vector_columns(vector, layer).keys():
	    if not flags['c']:
		grass.fatal((_("Cannot create column <%s> (already present). ") % currcolumn) +
			    _("Use -c flag to update values in this column."))
	else:
	    if i == "n":
		coltype = "INTEGER"
	    else:
		coltype = "DOUBLE PRECISION"
	    addcols.append(currcolumn + ' ' + coltype)

    if addcols:
	grass.verbose(_("Adding columns '%s'") % addcols)
	if grass.run_command('v.db.addcolumn', map = vector, columns = addcols) != 0:
	    grass.fatal(_("Adding columns failed. Exiting."))

    # calculate statistics:
    grass.message(_("Processing data (%d categories)...") % number)

    # get rid of any earlier attempts
    grass.try_remove(sqltmp)

    colnames = []
    for var in basecols + extracols:
	colname = '%s_%s' % (colprefix, var)
	if dbfdriver:
	    colname = colname[:10]
	colnames.append(colname)

    ntabcols = len(colnames)

    # do extended stats?
    if flags['e']:
	extstat = 'e'
    else:
	extstat = ""
	
    f = file(sqltmp, 'w')

    # do the stats
    p = grass.pipe_command('r.univar', flags = 't' + 'g' + extstat, map = raster, 
                      zones = rastertmp, percentile = percentile, fs = ';')

    first_line = 1
    for line in p.stdout:
	if first_line:
	    first_line = 0
	    continue

	vars = line.rstrip('\r\n').split(';')

	f.write("UPDATE %s SET" % fi['table'])
	i = 2
	first_var = 1
	for colname in colnames:
	    value = vars[i]
	    # convert nan, +nan, -nan to NULL
	    if value.lower().endswith('nan'):
		value = 'NULL'
	    if not first_var:
		f.write(" , ")
	    else:
		first_var = 0
	    f.write(" %s=%s" % (colname, value))
	    i += 1
	    # skip n_null_cells, mean_of_abs, sum_of_abs
	    if i == 3 or i == 8 or i == 13:
		i += 1

	f.write(" WHERE %s=%s;\n" % (fi['key'], vars[0]))

    p.wait()
    f.close()

    grass.message(_("Updating the database ..."))
    exitcode = grass.run_command('db.execute', input = sqltmp,
				 database = fi['database'], driver = fi['driver'])

    grass.run_command('g.remove', rast = 'MASK', quiet = True, stderr = nuldev)

    if exitcode == 0:
	grass.message((_("Statistics calculated from raster map <%s>") % raster) +
		      (_(" and uploaded to attribute table of vector map <%s>.") % vector))
    else:
	grass.warning(_("Failed to upload statistics to attribute table of vector map <%s>.") % vector)
    
    
    sys.exit(exitcode)
Exemple #46
0
def main():
    if flags['r'] and flags['s']:
	grass.fatal(_("Either -r or -s flag"))

    mapname = options['map']
    option = options['option']
    layer = options['layer']
    units = options['units']

    nuldev = file(os.devnull, 'w')

    if not grass.find_file(mapname, 'vector')['file']:
	grass.fatal(_("Vector map '%s' not found in mapset search path.") % mapname)

    colnames = grass.vector_columns(mapname, layer, getDict = False, stderr = nuldev)
    if not colnames:
	colnames = ['cat']

    if option == 'coor':
	columns = ['dummy1','dummy2','dummy3']
	extracolnames = ['x','y','z']
    else:
	columns = ['dummy1']
	extracolnames = [option]

    if units in ['p','percent']:
	unitsp = 'meters'
    elif units:
	unitsp = units
    else:
	unitsp = None

    # NOTE: we suppress -1 cat and 0 cat

    if colnames:
	p = grass.pipe_command('v.db.select', quiet = True, flags='c', map = mapname, layer = layer)
	records1 = []
	for line in p.stdout:
	    cols = line.rstrip('\r\n').split('|')
	    if cols[0] == '0':
		continue
	    records1.append([int(cols[0])] + cols[1:])
	p.wait()
        if p.returncode != 0:
            sys.exit(1)
        
	records1.sort()

	if len(records1) == 0:
            try:
                f = grass.vector_db(map = mapname)[int(layer)]
                grass.fatal(_("There is a table connected to input vector map '%s', but"
                              "there are no categories present in the key column '%s'. Consider using"
                              "v.to.db to correct this.") % (mapname, f['key']))
            except KeyError:
                pass

	#fetch the requested attribute sorted by cat:
	p = grass.pipe_command('v.to.db', flags = 'p',
                               quiet = True,
			       map = mapname, option = option, columns = columns,
			       layer = layer, units = unitsp)
	records2 = []
	for line in p.stdout:
	    fields = line.rstrip('\r\n').split('|')
	    if fields[0] in ['cat', '-1', '0']:
		continue
	    records2.append([int(fields[0])] + fields[1:])
	p.wait()
	records2.sort()

	#make pre-table
	records3 = [r1 + r2[1:] for r1, r2 in zip(records1, records2)]
    else:
	records1 = []
        p = grass.pipe_command('v.category', inp = mapname, layer = layer, option = 'print')
	for line in p.stdout:
	    field = int(line.rstrip())
	    if field > 0:
		records1.append(field)
	p.wait()
	records1.sort()
	records1 = uniq(records1)

        #make pre-table
	p = grass.pipe_command('v.to.db', flags = 'p',
			       map = mapname, option = option, columns = columns,
			       layer = layer, units = unitsp)
	records3 = []
	for line in p.stdout:
	    fields = line.split('|')
	    if fields[0] in ['cat', '-1', '0']:
		continue
	    records3.append([int(fields[0])] + fields[1:])
	p.wait()
	records3.sort()

    # print table header
    sys.stdout.write('|'.join(colnames + extracolnames) + '\n')

    #make and print the table:
    numcols = len(colnames) + len(extracolnames)

    # calculate percents if requested
    if units != '' and units in ['p','percent']:
	# calculate total area value
	areatot = 0
	for r in records3:
	    areatot += float(r[-1])

	# calculate area percentages
	records4 = [float(r[-1]) * 100 / areatot for r in records3]
	records3 = [r1 + [r4] for r1, r4 in zip(records1, records4)]

    if flags['s']:
	# sort
	records3.sort(key = lambda r: (r[0], r[-1]))
    elif flags['r']:
	# reverse sort
	records3.sort(key = lambda r: (r[0], r[-1]), reverse = True)

    for r in records3:
	sys.stdout.write('|'.join(map(str,r)) + '\n')