def main(): map = options['map'] layer = options['layer'] column = options['column'] otable = options['otable'] ocolumn = options['ocolumn'] f = grass.vector_layer_db(map, layer) maptable = f['table'] database = f['database'] driver = f['driver'] if driver == 'dbf': grass.fatal(_("JOIN is not supported for tables stored in DBF format")) if not maptable: grass.fatal(_("There is no table connected to this map. Unable to join any column.")) if not grass.vector_columns(map, layer).has_key(column): grass.fatal(_("Column <%s> not found in table <%s> at layer <%s>") % (column, map, layer)) all_cols_ot = grass.db_describe(otable, driver = driver, database = database)['cols'] all_cols_tt = grass.vector_columns(map, int(layer)).keys() select = "SELECT $colname FROM $otable WHERE $otable.$ocolumn=$table.$column" template = string.Template("UPDATE $table SET $colname=(%s);" % select) for col in all_cols_ot: # Skip the vector column which is used for join colname = col[0] if colname == column: continue # Sqlite 3 does not support the precision number any more if len(col) > 2 and driver != "sqlite": coltype = "%s(%s)" % (col[1], col[2]) else: coltype = "%s" % col[1] colspec = "%s %s" % (colname, coltype) # Add only the new column to the table if colname not in all_cols_tt: if grass.run_command('v.db.addcolumn', map = map, columns = colspec, layer = layer) != 0: grass.fatal(_("Error creating column <%s>") % colname) stmt = template.substitute(table = maptable, column = column, otable = otable, ocolumn = ocolumn, colname = colname) grass.verbose(_("Updating column <%s> of vector map <%s>...") % (colname, map)) if grass.write_command('db.execute', stdin = stmt, input = '-', database = database, driver = driver) != 0: grass.fatal(_("Error filling column <%s>") % colname) # write cmd history: grass.vector_history(map)
def ImportMap(self, map, column): """ Imports GRASS map as SpatialPointsDataFrame and adds x/y columns to attribute table. Checks for NULL values in the provided column and exits if they are present.""" #@NOTE: new way with R - as it doesn't alter original data Rpointmap = robjects.r.readVECT(map, type='point') # checks if x,y columns are present in dataframe. If they do are present, but with different names, # they'll be duplicated. if "x" not in robjects.r.names(Rpointmap): # extract coordinates with S4 method coordinatesPreDF = robjects.r['as.data.frame'](robjects.r.coordinates(Rpointmap)) coordinatesDF = robjects.r['data.frame'](x=coordinatesPreDF.rx('coords.x1')[0], y=coordinatesPreDF.rx('coords.x2')[0]) # match coordinates with data slot of SpatialPointsDataFrame - maptools function # match is done on row.names Rpointmap = robjects.r.spCbind(Rpointmap, coordinatesDF) # GRASS checks for null values in the chosen column. R can hardly handle column as a variable, # looks for a hardcoded string. cols = grass.vector_columns(map=map, layer=1) nulls = int(grass.parse_command('v.univar', map=map, column=column, type='point', parse=(grass.parse_key_val, {'sep': ': '} ) )['number of NULL attributes']) if nulls > 0: grass.fatal( _("%d NULL value(s) in the selected column - unable to perform kriging.") % nulls) return Rpointmap
def ImportMap(self, map, column): """ Imports GRASS map as SpatialPointsDataFrame and adds x/y columns to attribute table. Checks for NULL values in the provided column and exits if they are present.""" #@NOTE: new way with R - as it doesn't alter original data Rpointmap = robjects.r.readVECT6(map, type='point') # checks if x,y columns are present in dataframe. If they do are present, but with different names, # they'll be duplicated. if "x" not in robjects.r.names(Rpointmap): # extract coordinates with S4 method coordinatesPreDF = robjects.r['as.data.frame']( robjects.r.coordinates(Rpointmap)) coordinatesDF = robjects.r['data.frame']( x=coordinatesPreDF.rx('coords.x1')[0], y=coordinatesPreDF.rx('coords.x2')[0]) # match coordinates with data slot of SpatialPointsDataFrame - maptools function # match is done on row.names Rpointmap = robjects.r.spCbind(Rpointmap, coordinatesDF) # GRASS checks for null values in the chosen column. R can hardly handle column as a variable, # looks for a hardcoded string. cols = grass.vector_columns(map=map, layer=1) nulls = int( grass.parse_command('v.univar', map=map, column=column, type='point', parse=(grass.parse_key_val, { 'sep': ': ' }))['number of NULL attributes']) if nulls > 0: grass.fatal( _("%d NULL value(s) in the selected column - unable to perform kriging." ) % nulls) return Rpointmap
def extract_data(input, output, cats, value): if len(cats) > 20000: newcol = "train_val_%s" % (os.getpid()) columns_existing = grass.vector_columns(options["input"]).keys() if newcol not in columns_existing: grass.run_command("v.db.addcolumn", map=input, columns="%s INTEGER" % (newcol)) n = 500 for i in range(0, len(cats), n): cats_list = cats[i:i + n] grass.run_command( "v.db.update", where="cat IN (%s)" % (",".join(cats_list)), map=input, column=newcol, value=value, quiet=True, ) grass.percent(i + n, len(cats), 1) grass.run_command( "v.extract", input=input, output=output, where="%s='%d'" % (newcol, value), ) else: grass.run_command("v.extract", input=input, cats=",".join(cats), output=output)
def main(): vector = options['map'] layer = options['layer'] column = options['column'] value = options['value'] qcolumn = options['qcolumn'] where = options['where'] mapset = grass.gisenv()['MAPSET'] # does map exist in CURRENT mapset? if not grass.find_file(vector, element='vector', mapset=mapset)['file']: grass.fatal(_("Vector map <%s> not found in current mapset") % vector) try: f = grass.vector_db(vector)[int(layer)] except KeyError: grass.fatal( _('There is no table connected to this map. Run v.db.connect or v.db.addtable first.' )) table = f['table'] database = f['database'] driver = f['driver'] # checking column types try: coltype = grass.vector_columns(vector, layer)[column]['type'] except KeyError: grass.fatal(_('Column <%s> not found') % column) if qcolumn: if value: grass.fatal(_('<value> and <qcolumn> are mutually exclusive')) # special case: we copy from another column value = qcolumn else: if not value: grass.fatal(_('Either <value> or <qcolumn> must be given')) # we insert a value if coltype.upper() not in ["INTEGER", "DOUBLE PRECISION"]: value = "'%s'" % value cmd = "UPDATE %s SET %s=%s" % (table, column, value) if where: cmd += " WHERE " + where grass.verbose("SQL: \"%s\"" % cmd) grass.write_command('db.execute', input='-', database=database, driver=driver, stdin=cmd) # write cmd history: grass.vector_history(vector) return 0
def cleanup(): grass.message(_("Cleaning up...")) if newcol: columns_existing = grass.vector_columns(options["input"]).keys() if newcol in columns_existing: grass.run_command("v.db.dropcolumn", map=options["input"], columns=newcol)
def main(): options, flags = gscript.parser() inputmap = options['input'] layer = options['layer'] outputmap = options['output'] sort_column = options['column'] reverse = True if flags['r']: reverse = False columns = gscript.vector_columns(inputmap) key_column = gscript.vector_layer_db(inputmap, layer)['key'] sort_index = columns[sort_column]['index']+2 sorted_cols = sorted(iter(columns.items()), key=lambda x_y: x_y[1]['index']) column_def="x DOUBLE PRECISION, y DOUBLE PRECISION, cat INTEGER" colnames = [] for colcount in range(1,len(sorted_cols)): name = sorted_cols[colcount][0] type = sorted_cols[colcount][1]['type'] if name == sort_column and (type != 'INTEGER' and type != 'DOUBLE PRECISION'): gscript.fatal('Sort column must be numeric') if name == key_column: continue colnames.append(name) column_def += ", %s %s" % (name, type) inpoints=gscript.read_command('v.out.ascii', in_=inputmap, columns=colnames, quiet=True) points=[] for line in inpoints.splitlines(): data = [num(x) for x in line.split('|')] points.append(data) points_sorted=sorted(points, key=lambda x: x[sort_index], reverse=reverse) outpoints = "" for list in points_sorted: outpoints+="|".join([str(x) for x in list])+"\n" gscript.write_command('v.in.ascii', input='-', stdin=outpoints, output=outputmap, x=1, y=2, cat=3, columns=column_def, quiet=True) gscript.run_command('v.db.dropcolumn', map=outputmap, columns='x,y', quiet=True) return 0
def main(): global output, tmp input = options['input'] output = options['output'] layer = options['layer'] column = options['column'] # setup temporary file tmp = str(os.getpid()) # does map exist? if not grass.find_file(input, element='vector')['file']: grass.fatal(_("Vector map <%s> not found") % input) if not column: grass.warning( _("No '%s' option specified. Dissolving based on category values from layer <%s>.") % ("column", layer)) grass.run_command('v.extract', flags='d', input=input, output=output, type='area', layer=layer) else: if int(layer) == -1: grass.warning(_("Invalid layer number (%d). " "Parameter '%s' specified, assuming layer '1'.") % (int(layer), 'column')) layer = '1' try: coltype = grass.vector_columns(input, layer)[column] except KeyError: grass.fatal(_('Column <%s> not found') % column) if coltype['type'] not in ('INTEGER', 'SMALLINT', 'CHARACTER', 'TEXT'): grass.fatal(_("Key column must be of type integer or string")) f = grass.vector_layer_db(input, layer) table = f['table'] tmpfile = '%s_%s' % (output, tmp) try: grass.run_command('v.reclass', input=input, output=tmpfile, layer=layer, column=column) grass.run_command('v.extract', flags='d', input=tmpfile, output=output, type='area', layer=layer) except CalledModuleError as e: grass.fatal(_("Final extraction steps failed." " Check above error messages and" " see following details:\n%s") % e) # write cmd history: grass.vector_history(output)
def main(): vector = options['map'] layer = options['layer'] column = options['column'] value = options['value'] qcolumn = options['qcolumn'] where = options['where'] mapset = grass.gisenv()['MAPSET'] # does map exist in CURRENT mapset? if not grass.find_file(vector, element = 'vector', mapset = mapset)['file']: grass.fatal(_("Vector map <%s> not found in current mapset") % vector) try: f = grass.vector_db(vector)[int(layer)] except KeyError: grass.fatal(_('There is no table connected to this map. Run v.db.connect or v.db.addtable first.')) table = f['table'] database = f['database'] driver = f['driver'] # checking column types try: coltype = grass.vector_columns(vector, layer)[column]['type'] except KeyError: grass.fatal(_('Column <%s> not found') % column) if qcolumn: if value: grass.fatal(_('<value> and <qcolumn> are mutually exclusive')) # special case: we copy from another column value = qcolumn else: if not value: grass.fatal(_('Either <value> or <qcolumn> must be given')) # we insert a value if coltype.upper() not in ["INTEGER", "DOUBLE PRECISION"]: value = "'%s'" % value cmd = "UPDATE %s SET %s=%s" % (table, column, value) if where: cmd += " WHERE " + where grass.verbose("SQL: \"%s\"" % cmd) grass.write_command('db.execute', input = '-', database = database, driver = driver, stdin = cmd) # write cmd history: grass.vector_history(vector) return 0
def __init__(self,**optionsandflags): '''Process all arguments and prepare processing''' # add all options and flags as attributes (only nonempty ones) self.options = {} for o in optionsandflags: if optionsandflags[o]!='': try: self.options[o] = int(optionsandflags[o]) # int except ValueError: try: self.options[o] = float(optionsandflags[o]) # float except ValueError: self.options[o] = optionsandflags[o]# str self.__dict__.update(self.options) # save region for convenience self.region = grass.region() # INPUT CHECK # input dir if not os.path.exists(self.datadir): grass.fatal('%s doesnt exisist!' %self.datadir) # climate stations columns cols=grass.vector_columns(self.climstations) for c in [self.fnames, self.stationelevation]: if c not in cols: grass.fatal('Cant find %s in table %s' %(c,self.climatestations)) # subbasins if self.elevation not in grass.vector_columns(self.subbasins): grass.fatal('Cant find %s in table %s' %(self.elevation,self.subbasins)) # no extension if 'ext' not in self.options: self.ext='' # check if INTERPOL.PAR can be written self.par = True parneeded = ['method','start','end','minnb','maxnb','maxdist','nodata'] if any([e not in self.options for e in parneeded]): grass.warning('''Won't write INTERPOL.PAR as any of these arguments is not set %s''' %(parneeded,)) self.par = False return
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 __init__(self,**optionsandflags): '''Process all arguments and prepare processing''' # add all options and flags as attributes (only nonempty ones) self.options = {} for o in optionsandflags: if optionsandflags[o]!='': self.options[o] = optionsandflags[o] self.__dict__.update(self.options) #TODO: check if accumulation map is an int and has minus values within subbasin MASK # make rast from subbasin vector self.subbasinrast = 'subbasin__rast' self.nextsubb_col = 'nextID' self.subb_col = 'subbasinID' # make sure subbasins are in current mapset VectMapset=self.subbasins.split('@') if len(VectMapset)==2 and VectMapset[1]!=grass.gisenv()['MAPSET']: grass.fatal('!!! %s needs to be in the current mapset because I will update its table !!!' %(self.subbasins)) # check what columns to use cols = grass.vector_columns(self.subbasins) if 'subbasinID' not in cols and 'cat' in cols: grun('v.db.addcolumn',map=self.subbasins,columns=self.subb_col+' int',quiet=True) grun('v.db.update', map=self.subbasins, column=self.subb_col, qcol='cat') # make rast grun('v.to.rast',input=self.subbasins,output=self.subbasinrast, use='attr', attrcolumn=self.subb_col,overwrite=True, quiet=True) # check fromto and prepare if 'fromto' in self.options: try: # make array a = np.array(self.fromto.split(','),dtype=int).reshape(-1,2) # add a 0 inlet column to it a = np.column_stack((a,np.zeros(len(a)))) # bring into rec array self.fromto = np.array(zip(*a.T),dtype=[('subbasinID',int), ('nextID',int),('inletID',int)]) except: grass.fatal('No integers or uneven number of values in fromto pairs. %s' %self.fromto) # check river course if 'rivercourse' in self.options: if type(self.rivercourse)==str: self.rivercourse = map(int,self.rivercourse.split(',')) elif type(self.rivercourse)==int: self.rivercourse = [self.rivercourse] return
def main(): map = options['map'] layer = options['layer'] columns = options['columns'] columns = [col.strip() for col in columns.split(',')] # does map exist in CURRENT mapset? mapset = grass.gisenv()['MAPSET'] exists = bool( grass.find_file(map, element='vector', mapset=mapset)['file']) if not exists: grass.fatal(_("Vector map <%s> not found in current mapset") % map) try: f = grass.vector_db(map)[int(layer)] except KeyError: grass.fatal( _("There is no table connected to this map. Run v.db.connect or v.db.addtable first." )) table = f['table'] database = f['database'] driver = f['driver'] column_existing = grass.vector_columns(map, int(layer)).keys() for col in columns: if not col: grass.fatal( _("There is an empty column. Did you leave a trailing comma?")) col_name = col.split(' ')[0].strip() if col_name in column_existing: grass.error( _("Column <%s> is already in the table. Skipping.") % col_name) continue grass.verbose(_("Adding column <%s> to the table") % col_name) p = grass.feed_command('db.execute', input='-', database=database, driver=driver) res = "ALTER TABLE {} ADD COLUMN {}".format(table, col) p.stdin.write(encode(res)) grass.debug(res) p.stdin.close() if p.wait() != 0: grass.fatal(_("Unable to add column <%s>.") % col) # write cmd history: grass.vector_history(map)
def create_river_network(invect, outvect): """ Prepare the input river network vector by: possibly smoothing the line, and adding several columns to the vector attribute table. THe added columns include start and end points for output to HEC-RAS """ thresh = options['threshold'] layer = options['layer'] if (flags['s']): # Perform smoothing of the input vector grass.run_command('v.generalize', input=invect, output=outvect, _method='snakes', threshold=thresh, overwrite=True, quiet=True) # Add a reach length column to the river vector # First check if column exists columns_exist = grass.vector_columns(outvect, int(layer)).keys() if not "reach_len" in columns_exist: grass.run_command('v.db.addcolumn', map=outvect, columns="reach_len DOUBLE PRECISION", quiet=True) # Also add columns for start and end point of each reach if not "start_x" in columns_exist: grass.run_command('v.db.addcolumn', map=outvect, columns="start_x DOUBLE PRECISION", quiet=True) if not "start_y" in columns_exist: grass.run_command('v.db.addcolumn', map=outvect, columns="start_y DOUBLE PRECISION", quiet=True) if not "start_elev" in columns_exist: grass.run_command('v.db.addcolumn', map=outvect, columns="start_elev DOUBLE PRECISION", quiet=True) if not "end_x" in columns_exist: grass.run_command('v.db.addcolumn', map=outvect, columns="end_x DOUBLE PRECISION", quiet=True) if not "end_y" in columns_exist: grass.run_command('v.db.addcolumn', map=outvect, columns="end_y DOUBLE PRECISION", quiet=True) if not "end_elev" in columns_exist: grass.run_command('v.db.addcolumn', map=outvect, columns="end_elev DOUBLE PRECISION", quiet=True) # Now update those columns grass.run_command('v.to.db',map=outvect, option="length", columns="reach_len", quiet=True) grass.run_command('v.to.db',map=outvect, option="start", columns="start_x,start_y",quiet=True) grass.run_command('v.to.db',map=outvect, option="end", columns="end_x,end_y", quiet=True) d=grass.read_command('v.db.select',map=outvect, separator="=", columns="cat,reach_len", flags="c") # Initialize dict of reach categories with their lengths # Each key in the dictionary is the cat of a river reach # each value is the length of that reach reach_cats=grass.parse_key_val(d, val_type=float) return reach_cats
def main(): map = options['map'] layer = options['layer'] columns = options['columns'] columns = [col.strip() for col in columns.split(',')] # does map exist in CURRENT mapset? mapset = grass.gisenv()['MAPSET'] exists = bool(grass.find_file(map, element='vector', mapset=mapset)['file']) if not exists: grass.fatal(_("Vector map <%s> not found in current mapset") % map) try: f = grass.vector_db(map)[int(layer)] except KeyError: grass.fatal( _("There is no table connected to this map. Run v.db.connect or v.db.addtable first.")) table = f['table'] database = f['database'] driver = f['driver'] column_existing = grass.vector_columns(map, int(layer)).keys() for col in columns: if not col: grass.fatal(_("There is an empty column. Did you leave a trailing comma?")) col_name = col.split(' ')[0].strip() if col_name in column_existing: grass.error(_("Column <%s> is already in the table. Skipping.") % col_name) continue grass.verbose(_("Adding column <%s> to the table") % col_name) p = grass.feed_command('db.execute', input='-', database=database, driver=driver) p.stdin.write("ALTER TABLE %s ADD COLUMN %s" % (table, col)) grass.debug("ALTER TABLE %s ADD COLUMN %s" % (table, col)) p.stdin.close() if p.wait() != 0: grass.fatal(_("Unable to add column <%s>.") % col) # write cmd history: grass.vector_history(map)
def main(): global output, tmp input = options['input'] output = options['output'] layer = options['layer'] column = options['column'] #### setup temporary file tmp = str(os.getpid()) # does map exist? if not grass.find_file(input, element = 'vector')['file']: grass.fatal(_("Vector map <%s> not found") % input) if not column: grass.run_command('v.extract', flags = 'd', input = input, output = output, type = 'area', layer = layer) else: try: coltype = grass.vector_columns(input, layer)[column] except KeyError: grass.fatal(_('Column <%s> not found') % column) if coltype['type'] not in ('INTEGER', 'CHARACTER'): grass.fatal(_("Key column must be of type integer or string")) f = grass.vector_layer_db(input, layer) table = f['table'] tmpfile = '%s_%s' % (output, tmp) if grass.run_command('v.reclass', input = input, output = tmpfile, layer = layer, column = column) == 0: grass.run_command('v.extract', flags = 'd', input = tmpfile, output = output, type = 'area', layer = layer) # write cmd history: grass.vector_history(output)
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 main(): # check if the map is in the current mapset mapset = grass.find_file(opt["map"], element="vector")["mapset"] if not mapset or mapset != grass.gisenv()["MAPSET"]: grass.fatal( _("Vector map <{}> not found in the current mapset").format( opt["map"])) # get list of existing columns try: columns = grass.vector_columns(opt["map"]).keys() except CalledModuleError as e: return 1 allowed_rasters = ("N2", "N5", "N10", "N20", "N50", "N100") # test input feature type vinfo = grass.vector_info_topo(opt["map"]) if vinfo["areas"] < 1 and vinfo["points"] < 1: grass.fatal( _("No points or areas found in input vector map <{}>").format( opt["map"])) # check area size limit check_area_size = float(opt["area_size"]) > 0 if check_area_size: area_col_name = "area_{}".format(os.getpid()) Module( "v.to.db", map=opt["map"], option="area", units="kilometers", columns=area_col_name, quiet=True, ) areas = Module( "v.db.select", flags="c", map=opt["map"], columns=area_col_name, where="{} > {}".format(area_col_name, opt["area_size"]), stdout_=grass.PIPE, ) large_areas = len(areas.outputs.stdout.splitlines()) if large_areas > 0: grass.warning( "{} areas larger than size limit will be skipped from computation" .format(large_areas)) # extract multi values to points for rast in opt["return_period"].split(","): # check valid rasters name = grass.find_file(rast, element="cell")["name"] if not name: grass.warning("Raster map <{}> not found. " "Skipped.".format(rast)) continue if name not in allowed_rasters: grass.warning("Raster map <{}> skipped. " "Allowed: {}".format(rast, allowed_rasters)) continue # perform zonal statistics grass.message("Processing <{}>...".format(rast)) table = "{}_table".format(name) if vinfo["areas"] > 0: Module( "v.rast.stats", flags="c", map=opt["map"], raster=rast, column_prefix=name, method="average", quiet=True, ) # handle NULL values (areas smaller than raster resolution) null_values = Module( "v.db.select", map=opt["map"], columns="cat", flags="c", where="{}_average is NULL".format(name), stdout_=grass.PIPE, ) cats = null_values.outputs.stdout.splitlines() if len(cats) > 0: grass.warning( _("Input vector map <{}> contains very small areas (smaller than " "raster resolution). These areas will be proceeded by querying " "single raster cell.").format(opt["map"])) Module( "v.what.rast", map=opt["map"], raster=rast, type="centroid", column="{}_average".format(name), where="{}_average is NULL".format(name), quiet=True, ) else: # -> points Module( "v.what.rast", map=opt["map"], raster=rast, column="{}_average".format(name), quiet=True, ) # add column to the attribute table if not exists rl = float(opt["rainlength"]) field_name = "H_{}T{}".format(name, opt["rainlength"]) if field_name not in columns: Module( "v.db.addcolumn", map=opt["map"], columns="{} double precision".format(field_name), ) # determine coefficient for calculation a, c = coeff(rast, rl) if a is None or c is None: grass.fatal("Unable to calculate coefficients") # calculate output values, update attribute table coef = a * rl**(1 - c) expression = "{}_average * {}".format(name, coef) Module("v.db.update", map=opt["map"], column=field_name, query_column=expression) if check_area_size: Module( "v.db.update", map=opt["map"], column=field_name, value="-1", where="{} > {}".format(area_col_name, opt["area_size"]), ) # remove unused column Module("v.db.dropcolumn", map=opt["map"], columns="{}_average".format(name)) if check_area_size: # remove unused column Module("v.db.dropcolumn", map=opt["map"], columns=area_col_name) return 0
def set_up_columns(vector, layer, percentile, colprefix, basecols, dbfdriver, c): """Get columns-depending variables and create columns, if needed. :param vector: name of vector map or data source for direct OGR access :param layer: layer number or name :param percentile: percentile to calculate :param colprefix: column prefix for new attribute columns :param basecols: the methods to use :param dbfdriver: boolean saying if the driver is dbf :param c: boolean saying if it should continue if upload column(s) already exist :return: colprefix, variables_dbf, variables, colnames, extstat """ # 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 variables_dbf = {} if dbfdriver: colprefix = colprefix[:6] # 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': 3, '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 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.")) return colprefix, variables_dbf, variables, colnames, extstat
def main(): global tmp, tmpname, rastertmp1, rastertmp2, rastertmp3 rastertmp1 = False rastertmp2 = False rastertmp3 = False #### setup temporary files tmp = grass.tempfile() # we need a random name tmpname = grass.basename(tmp) vector = options["vector"] layer = options["layer"] column = options["column"] weight = options["weight"] output = options["output"] # vector exists? result = grass.find_file(vector, element="vector") if len(result["name"]) == 0: grass.fatal(_("Input vector <%s> not found") % vector) # raster exists? result = grass.find_file(weight, element="cell") if len(result["name"]) == 0: grass.fatal(_("Input weight raster <%s> not found") % weight) # column exists ? if column not in grass.vector_columns(vector, layer).keys(): grass.fatal( _("Column does not exist for vector <%s>, layer %s") % (vector, layer)) # is column numeric? coltype = grass.vector_columns(vector, layer)[column]["type"] if coltype not in ("INTEGER", "DOUBLE PRECISION"): grass.fatal(_("Column must be numeric")) # rasterize with cats (will be base layer) # strip off mapset for tmp output vector_basename = vector.split("@")[0] rastertmp1 = "%s_%s_1" % (vector_basename, tmpname) try: grass.run_command("v.to.rast", input=vector, output=rastertmp1, use="cat", quiet=True) except CalledModuleError: grass.fatal(_("An error occurred while converting vector to raster")) # rasterize with column rastertmp2 = "%s_%s_2" % (vector_basename, tmpname) try: grass.run_command( "v.to.rast", input=vector, output=rastertmp2, use="attr", layer=layer, attrcolumn=column, quiet=True, ) except CalledModuleError: grass.fatal(_("An error occurred while converting vector to raster")) # zonal statistics rastertmp3 = "%s_%s_3" % (vector_basename, tmpname) try: grass.run_command( "r.stats.zonal", base=rastertmp1, cover=weight, method="sum", output=rastertmp3, quiet=True, ) except CalledModuleError: grass.fatal(_("An error occurred while calculating zonal statistics")) # weighted interpolation exp = "$output = if($sumweight == 0, if(isnull($area_val), null(), 0), double($area_val) * $weight / $sumweight)" grass.mapcalc(exp, output=output, sumweight=rastertmp3, area_val=rastertmp2, weight=weight) sys.exit(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')
def main(): map = options['map'] layer = options['layer'] columns = options['columns'].split(',') mapset = grass.gisenv()['MAPSET'] # does map exist in CURRENT mapset? if not grass.find_file(map, element='vector', mapset=mapset)['file']: grass.fatal(_("Vector map <%s> not found in current mapset") % map) f = grass.vector_layer_db(map, layer) table = f['table'] keycol = f['key'] database = f['database'] driver = f['driver'] if not table: grass.fatal(_("There is no table connected to the input vector map. " "Unable to delete any column. Exiting.")) if keycol in columns: grass.fatal(_("Unable to delete <%s> column as it is needed to keep table <%s> " "connected to the input vector map <%s>") % (keycol, table, map)) for column in columns: if column not in grass.vector_columns(map, layer): grass.warning(_("Column <%s> not found in table <%s>. Skipped") % (column, table)) continue if driver == "sqlite": # echo "Using special trick for SQLite" # http://www.sqlite.org/faq.html#q11 colnames = [] coltypes = [] for f in grass.db_describe(table, database=database, driver=driver)['cols']: if f[0] == column: continue colnames.append(f[0]) coltypes.append("%s %s" % (f[0], f[1])) colnames = ", ".join(colnames) coltypes = ", ".join(coltypes) cmds = [ "BEGIN TRANSACTION", "CREATE TEMPORARY TABLE ${table}_backup(${coldef})", "INSERT INTO ${table}_backup SELECT ${colnames} FROM ${table}", "DROP TABLE ${table}", "CREATE TABLE ${table}(${coldef})", "INSERT INTO ${table} SELECT ${colnames} FROM ${table}_backup", "CREATE UNIQUE INDEX ${table}_cat ON ${table} (${keycol} )", "DROP TABLE ${table}_backup", "COMMIT" ] tmpl = string.Template(';\n'.join(cmds)) sql = tmpl.substitute(table=table, coldef=coltypes, colnames=colnames, keycol=keycol) else: sql = "ALTER TABLE %s DROP COLUMN %s" % (table, column) try: grass.write_command('db.execute', input='-', database=database, driver=driver, stdin=sql) except CalledModuleError: grass.fatal(_("Deleting column failed")) # write cmd history: grass.vector_history(map)
def main(): options, flags = gscript.parser() inputmap = options["input"] layer = options["layer"] outputmap = options["output"] sort_column = options["column"] reverse = True if flags["r"]: reverse = False columns = gscript.vector_columns(inputmap) key_column = gscript.vector_layer_db(inputmap, layer)["key"] sort_index = columns[sort_column]["index"] + 2 sorted_cols = sorted(iter(columns.items()), key=lambda x_y: x_y[1]["index"]) column_def = "x DOUBLE PRECISION, y DOUBLE PRECISION, cat INTEGER" colnames = [] for colcount in range(1, len(sorted_cols)): name = sorted_cols[colcount][0] type = sorted_cols[colcount][1]["type"] if name == sort_column and (type != "INTEGER" and type != "DOUBLE PRECISION"): gscript.fatal("Sort column must be numeric") if name == key_column: continue colnames.append(name) column_def += ", %s %s" % (name, type) inpoints = gscript.read_command("v.out.ascii", in_=inputmap, columns=colnames, quiet=True) points = [] for line in inpoints.splitlines(): data = [num(x) for x in line.split("|")] points.append(data) points_sorted = sorted(points, key=lambda x: x[sort_index], reverse=reverse) outpoints = "" for list in points_sorted: outpoints += "|".join([str(x) for x in list]) + "\n" gscript.write_command( "v.in.ascii", input="-", stdin=outpoints, output=outputmap, x=1, y=2, cat=3, columns=column_def, quiet=True, ) gscript.run_command("v.db.dropcolumn", map=outputmap, columns="x,y", quiet=True) return 0
def main(): options, flags = gs.parser() points_name = options["points"] points_layer = options["points_layer"] points_columns = [] if options["points_columns"]: points_columns = options["points_columns"].split(",") # TODO: Add check points exist before we query the metadata. input_vector_columns = gs.vector_columns(points_name, points_layer) if not points_columns: # Get all numeric columns from the table. # Get only the names ordered in the same as in the database. all_column_names = gs.vector_columns(points_name, points_layer, getDict=False) for name in all_column_names: # TODO: Find out what is the key column (usually cat) and skip it. column_type = input_vector_columns[name]["type"] if sql_type_is_numeric(column_type): points_columns.append(name) else: # Check the user provided columns. for name in points_columns: try: column_info = input_vector_columns[name] except KeyError: gs.fatal( _("Column <{name}> not found in vector map <{points_name}>," " layer <{points_layer}>").format(**locals())) column_type = column_info["type"] if not sql_type_is_numeric(column_type): gs.fatal( _("Column <{name}> in <{points_name}> is {column_type}" " which is not a numeric type").format(**locals())) methods = options["method"].split(",") stats_columns_names = [] num_new_columns = len(points_columns) * len(methods) if options["stats_columns"]: stats_columns_names = options["stats_columns"].split(",") names_provided = len(stats_columns_names) if names_provided != num_new_columns: gs.fatal( _("Number of provided stats_columns ({names_provided})" " does not correspond to number of names needed" " for every combination of points_columns and methods" " ({num_points_columns} * {num_methods} = {names_needed})"). format( names_provided=names_provided, num_points_columns=len(points_columns), num_methods=len(methods), names_needed=num_new_columns, )) num_unique_names = len(set(stats_columns_names)) if names_provided != num_unique_names: gs.fatal( _("Names in stats_columns are not unique" " ({names_provided} items provied" " but only {num_unique_names} are unique)").format( names_provided=names_provided, num_unique_names=num_unique_names, )) modified_options = options.copy() # Remove options we are handling here. del modified_options["points_columns"] del modified_options["stats_columns"] del modified_options["method"] # Note that the count_column is mandatory for v.vect.stats, # so it is simply computed more than once. Ideally, it would # be optional for this module which would probably mean better handling of # number of point and n in statistions in v.vect.stats (unless we simply # use temporary name and drop the column at the end). # The product function advances the rightmost element on every iteration, # so first we get all methods for one column. This is important to # the user if stats_columns is provided. for i, (points_column, method) in enumerate(product(points_columns, methods)): if stats_columns_names: stats_column_name = stats_columns_names[i] else: stats_column_name = f"{points_column}_{method}" gs.run_command( "v.vect.stats", method=method, points_column=points_column, stats_column=stats_column_name, quiet=True, **modified_options, errors="exit", ) gs.percent(i, num_new_columns, 1) gs.percent(1, 1, 1) return 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)
def main(): vector = options["map"] layer = options["layer"] column = options["column"] value = options["value"] qcolumn = options["query_column"] where = options["where"] sqlitefile = options["sqliteextra"] mapset = grass.gisenv()["MAPSET"] # does map exist in CURRENT mapset? if not grass.find_file(vector, element="vector", mapset=mapset)["file"]: grass.fatal(_("Vector map <%s> not found in current mapset") % vector) try: f = grass.vector_db(vector)[int(layer)] except KeyError: grass.fatal(_("There is no table connected to this map. Run v.db.connect or v.db.addtable first.")) table = f["table"] database = f["database"] driver = f["driver"] # check for SQLite backend for extra functions if sqlitefile and driver != "sqlite": grass.fatal(_("Use of libsqlitefunctions only with SQLite backend")) if driver == "sqlite" and sqlitefile: if not os.access(sqlitefile, os.R_OK): grass.fatal(_("File <%s> not found") % sqlitefile) # checking column types try: coltype = grass.vector_columns(vector, layer)[column]["type"] except KeyError: grass.fatal(_("Column <%s> not found") % column) if qcolumn: if value: grass.fatal(_("<value> and <qcolumn> are mutually exclusive")) # special case: we copy from another column value = qcolumn else: if not value: grass.fatal(_("Either <value> or <qcolumn> must be given")) # we insert a value if coltype.upper() not in ["INTEGER", "DOUBLE PRECISION"]: value = "'%s'" % value cmd = "UPDATE %s SET %s=%s" % (table, column, value) if where: cmd += " WHERE " + where # SQLite: preload extra functions from extension lib if provided by user if sqlitefile: sqliteload = "SELECT load_extension('%s');\n" % sqlitefile cmd = sqliteload + cmd grass.verbose('SQL: "%s"' % cmd) grass.write_command("db.execute", input="-", database=database, driver=driver, stdin=cmd) # write cmd history: grass.vector_history(vector) return 0
def main(): # check if the map is in the current mapset mapset = grass.find_file(opt['map'], element='vector')['mapset'] if not mapset or mapset != grass.gisenv()['MAPSET']: grass.fatal( _("Vector map <{}> not found in the current mapset").format( opt['map'])) # get list of existing columns try: columns = grass.vector_columns(opt['map']).keys() except CalledModuleError as e: return 1 allowed_rasters = ('N2', 'N5', 'N10', 'N20', 'N50', 'N100') # test input feature type vinfo = grass.vector_info_topo(opt['map']) if vinfo['areas'] < 1 and vinfo['points'] < 1: grass.fatal( _("No points or areas found in input vector map <{}>").format( opt['map'])) # check area size limit check_area_size = float(opt['area_size']) > 0 if check_area_size: area_col_name = 'area_{}'.format(os.getpid()) Module('v.to.db', map=opt['map'], option='area', units='kilometers', columns=area_col_name, quiet=True) areas = Module('v.db.select', flags='c', map=opt['map'], columns=area_col_name, where='{} > {}'.format(area_col_name, opt['area_size']), stdout_=grass.PIPE) large_areas = len(areas.outputs.stdout.splitlines()) if large_areas > 0: grass.warning( '{} areas larger than size limit will be skipped from computation' .format(large_areas)) # extract multi values to points for rast in opt['return_period'].split(','): # check valid rasters name = grass.find_file(rast, element='cell')['name'] if not name: grass.warning('Raster map <{}> not found. ' 'Skipped.'.format(rast)) continue if name not in allowed_rasters: grass.warning('Raster map <{}> skipped. ' 'Allowed: {}'.format(rast, allowed_rasters)) continue # perform zonal statistics grass.message('Processing <{}>...'.format(rast)) table = '{}_table'.format(name) if vinfo['areas'] > 0: Module('v.rast.stats', flags='c', map=opt['map'], raster=rast, column_prefix=name, method='average', quiet=True) # handle NULL values (areas smaller than raster resolution) null_values = Module('v.db.select', map=opt['map'], columns='cat', flags='c', where="{}_average is NULL".format(name), stdout_=grass.PIPE) cats = null_values.outputs.stdout.splitlines() if len(cats) > 0: grass.warning( _("Input vector map <{}> contains very small areas (smaller than " "raster resolution). These areas will be proceeded by querying " "single raster cell.").format(opt['map'])) Module('v.what.rast', map=opt['map'], raster=rast, type='centroid', column='{}_average'.format(name), where="{}_average is NULL".format(name), quiet=True) else: # -> points Module('v.what.rast', map=opt['map'], raster=rast, column='{}_average'.format(name), quiet=True) # add column to the attribute table if not exists rl = float(opt['rainlength']) field_name = 'H_{}T{}'.format(name, opt['rainlength']) if field_name not in columns: Module('v.db.addcolumn', map=opt['map'], columns='{} double precision'.format(field_name)) # determine coefficient for calculation a, c = coeff(rast, rl) if a is None or c is None: grass.fatal("Unable to calculate coefficients") # calculate output values, update attribute table coef = a * rl**(1 - c) expression = '{}_average * {}'.format(name, coef) Module('v.db.update', map=opt['map'], column=field_name, query_column=expression) if check_area_size: Module('v.db.update', map=opt['map'], column=field_name, value='-1', where='{} > {}'.format(area_col_name, opt['area_size'])) # remove unused column Module('v.db.dropcolumn', map=opt['map'], columns='{}_average'.format(name)) if check_area_size: # remove unused column Module('v.db.dropcolumn', map=opt['map'], columns=area_col_name) return 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)
def main(): map = options['map'] layer = options['layer'] column = options['column'] otable = options['otable'] ocolumn = options['ocolumn'] if options['scolumns']: scolumns = options['scolumns'].split(',') else: scolumns = None f = grass.vector_layer_db(map, layer) maptable = f['table'] database = f['database'] driver = f['driver'] if driver == 'dbf': grass.fatal(_("JOIN is not supported for tables stored in DBF format")) if not maptable: grass.fatal(_("There is no table connected to this map. Unable to join any column.")) # check if column is in map table if not grass.vector_columns(map, layer).has_key(column): grass.fatal(_("Column <%s> not found in table <%s>") % (column, maptable)) # describe other table all_cols_ot = grass.db_describe(otable, driver = driver, database = database)['cols'] # check if ocolumn is on other table if ocolumn not in [ocol[0] for ocol in all_cols_ot]: grass.fatal(_("Column <%s> not found in table <%s>") % (ocolumn, otable)) # determine columns subset from other table if not scolumns: # select all columns from other table cols_to_add = all_cols_ot else: cols_to_add = [] # check if scolumns exists in the other table for scol in scolumns: found = False for col_ot in all_cols_ot: if scol == col_ot[0]: found = True cols_to_add.append(col_ot) break if not found: grass.warning(_("Column <%s> not found in table <%s>.") % (scol, otable)) all_cols_tt = grass.vector_columns(map, int(layer)).keys() select = "SELECT $colname FROM $otable WHERE $otable.$ocolumn=$table.$column" template = string.Template("UPDATE $table SET $colname=(%s);" % select) for col in cols_to_add: # skip the vector column which is used for join colname = col[0] if colname == column: continue # Sqlite 3 does not support the precision number any more if len(col) > 2 and driver != "sqlite": coltype = "%s(%s)" % (col[1], col[2]) else: coltype = "%s" % col[1] colspec = "%s %s" % (colname, coltype) # add only the new column to the table if colname not in all_cols_tt: if grass.run_command('v.db.addcolumn', map = map, columns = colspec, layer = layer) != 0: grass.fatal(_("Error creating column <%s>") % colname) stmt = template.substitute(table = maptable, column = column, otable = otable, ocolumn = ocolumn, colname = colname) grass.debug(stmt, 1) grass.verbose(_("Updating column <%s> of vector map <%s>...") % (colname, map)) if grass.write_command('db.execute', stdin = stmt, input = '-', database = database, driver = driver) != 0: grass.fatal(_("Error filling column <%s>") % colname) # write cmd history grass.vector_history(map) return 0
def main(): vector = options['map'] layer = options['layer'] column = options['column'] value = options['value'] qcolumn = options['query_column'] where = options['where'] sqlitefile = options['sqliteextra'] mapset = grass.gisenv()['MAPSET'] # does map exist in CURRENT mapset? if not grass.find_file(vector, element='vector', mapset=mapset)['file']: grass.fatal(_("Vector map <%s> not found in current mapset") % vector) try: f = grass.vector_db(vector)[int(layer)] except KeyError: grass.fatal( _('There is no table connected to this map. Run v.db.connect or v.db.addtable first.' )) table = f['table'] database = f['database'] driver = f['driver'] # check for SQLite backend for extra functions if sqlitefile and driver != "sqlite": grass.fatal(_("Use of libsqlitefunctions only with SQLite backend")) if driver == "sqlite" and sqlitefile: if not os.access(sqlitefile, os.R_OK): grass.fatal(_("File <%s> not found") % sqlitefile) # checking column types try: coltype = grass.vector_columns(vector, layer)[column]['type'] except KeyError: grass.fatal(_('Column <%s> not found') % column) if qcolumn: if value: grass.fatal(_('<value> and <qcolumn> are mutually exclusive')) # special case: we copy from another column value = qcolumn else: if not value: grass.fatal(_('Either <value> or <qcolumn> must be given')) # we insert a value if coltype.upper() not in ["INTEGER", "DOUBLE PRECISION"]: value = "'%s'" % value cmd = "UPDATE %s SET %s=%s" % (table, column, value) if where: cmd += " WHERE " + where # SQLite: preload extra functions from extension lib if provided by user if sqlitefile: sqliteload = "SELECT load_extension('%s');\n" % sqlitefile cmd = sqliteload + cmd grass.verbose("SQL: \"%s\"" % cmd) grass.write_command('db.execute', input='-', database=database, driver=driver, stdin=cmd) # write cmd history: grass.vector_history(vector) return 0
def main(): global output, tmp input = options["input"] output = options["output"] layer = options["layer"] column = options["column"] # setup temporary file tmp = str(os.getpid()) # does map exist? if not grass.find_file(input, element="vector")["file"]: grass.fatal(_("Vector map <%s> not found") % input) if not column: grass.warning( _("No '%s' option specified. Dissolving based on category values from layer <%s>." ) % ("column", layer)) grass.run_command("v.extract", flags="d", input=input, output=output, type="area", layer=layer) else: if int(layer) == -1: grass.warning( _("Invalid layer number (%d). " "Parameter '%s' specified, assuming layer '1'.") % (int(layer), "column")) layer = "1" try: coltype = grass.vector_columns(input, layer)[column] except KeyError: grass.fatal(_("Column <%s> not found") % column) if coltype["type"] not in ("INTEGER", "SMALLINT", "CHARACTER", "TEXT"): grass.fatal(_("Key column must be of type integer or string")) f = grass.vector_layer_db(input, layer) table = f["table"] tmpfile = "%s_%s" % (output, tmp) try: grass.run_command("v.reclass", input=input, output=tmpfile, layer=layer, column=column) grass.run_command( "v.extract", flags="d", input=tmpfile, output=output, type="area", layer=layer, ) except CalledModuleError as e: grass.fatal( _("Final extraction steps failed." " Check above error messages and" " see following details:\n%s") % e) # write cmd history: grass.vector_history(output)
def main(): """Process command line parameters and update the table""" options, flags = gs.parser() vector = options["map"] layer = options["layer"] where = options["where"] column = options["column"] expression = options["expression"] condition = options["condition"] functions_file = options["functions"] # Map needs to be in the current mapset mapset = gs.gisenv()["MAPSET"] if not gs.find_file(vector, element="vector", mapset=mapset)["file"]: gs.fatal( _("Vector map <{vector}> does not exist or is not in the current mapset" "(<{mapset}>) and therefore it cannot be modified").format( **locals())) # Map+layer needs to have a table connected try: # TODO: Support @OGR vector maps? Probably not supported by db.execute anyway. db_info = gs.vector_db(vector)[int(layer)] except KeyError: gs.fatal( _("There is no table connected to map <{vector}> (layer <{layer}>)." " Use v.db.connect or v.db.addtable to add it.").format( **locals())) table = db_info["table"] database = db_info["database"] driver = db_info["driver"] columns = gs.vector_columns(vector, layer) # Check that column exists try: column_info = columns[column] except KeyError: gs.fatal( _("Column <{column}> not found. Use v.db.addcolumn to create it."). format(column=column)) column_type = column_info["type"] # Check that optional function file exists if functions_file: if not os.access(functions_file, os.R_OK): gs.fatal(_("File <{file}> not found").format(file=functions_file)) # Define Python functions # Here we need the full-deal eval and exec functions and can't sue less # general alternatives such as ast.literal_eval. def expression_function(**kwargs): return eval(expression, globals(), kwargs) # pylint: disable=eval-used def condition_function(**kwargs): return eval(condition, globals(), kwargs) # pylint: disable=eval-used # TODO: Add error handling for failed imports. if options["packages"]: packages = options["packages"].split(",") for package in packages: # pylint: disable=exec-used exec(f"import {package}", globals(), globals()) if flags["s"]: exec(f"from {package} import *", globals(), globals()) # TODO: Add error handling for invalid syntax. if functions_file: with open(functions_file) as file: exec(file.read(), globals(), globals()) # pylint: disable=exec-used # Get table contents if not where: # The condition needs to be None, an empty string is passed through. where = None if gs.version()["version"] < "7.9": sep = "|" # Only one char sep for Python csv package. null = "NULL" csv_text = gs.read_command( "v.db.select", map=vector, layer=layer, separator=sep, null=null, where=where, ) table_contents = csv_loads(csv_text, delimeter=sep, null=null) else: # TODO: XXX is a workaround for a bug in v.db.select -j json_text = gs.read_command("v.db.select", map=vector, layer=layer, flags="j", null="XXX", where=where) table_contents = json.loads(json_text) cmd = python_to_transaction( table=table, table_contents=table_contents, column=column, column_type=column_type, expression=expression, expression_function=expression_function, condition=condition, condition_function=condition_function, ensure_lowercase=not flags["u"], ) # Messages if len(cmd) == 2: gs.message( "No rows to update. Try a different SQL where or Python condition." ) elif len(cmd) > 2: # First and last statement gs.verbose(f'Using SQL: "{cmd[1]}...{cmd[-2]}"') # The newline is needed for successful execution/reading of many statements. # TODO: Add error handling when there is a syntax error due to wrongly # generated SQL statement and/or sanitize the value in update more. gs.write_command("db.execute", input="-", database=database, driver=driver, stdin="\n".join(cmd)) gs.vector_history(vector)
def main(): # Get the options input = options["input"] timestamp_column = options["timestamp_column"] columns = options["column"] layer = options["layer"] where = options["where"] strds = options["strds"] tempwhere = options["t_where"] i_flag = flags["i"] if where == "" or where == " " or where == "\n": where = None # overwrite = grass.overwrite() # Set verbosity level # quiet = True # if grass.verbosity() > 2: # quiet = False grass.warning(_('This addon is experimental!')) # Check DB connection for input vector map dbcon = grass.vector_layer_db(input, layer) # Check the number of sample strds and the number of columns strds_names = strds.split(",") column_names = columns.split(",") if not len(column_names) == len(strds_names): grass.fatal(_('Number of columns and number of STRDS does not match.')) # Check type of timestamp column cols = grass.vector_columns(input, layer=layer) if timestamp_column not in cols.keys(): grass.fatal( _('Could not find column {} \ in table connected to vector map {} \ at layer {}'.format(timestamp_column, input, layer))) if cols[timestamp_column]['type'] != 'DATE': if dbcon['driver'] != 'sqlite': # Note that SQLite does not have a DATE datatype and # and an index does not significantly speedup the process # (at least not with a couple of 100 points) grass.warning( _('Timestamp column is of type {}. \ It is recommended to use DATE type with an index. \ '.format(cols[timestamp_column]['type']))) # Make sure the temporal database exists tgis.init() # We need a database interface dbif = tgis.SQLDatabaseInterfaceConnection() dbif.connect() # Limit temporal extent to extent of points if no tempwhere is given if not tempwhere: extent = [] for stat in ('min', 'max'): tsql = "SELECT {}({}) FROM {}".format(stat, timestamp_column, dbcon['table']) extent.append(grass.read_command('db.select', flags='c', sql=tsql)) grass.verbose( _('Temporal extent of vector points map is \ {} to {}'.format(extent[0], extent[1]))) else: tempwhere = '({}) AND '.format(tempwhere) # Loop over STRDS counter = 0 for strds_name in strds_names: cur_strds = tgis.open_old_stds(strds_name, "strds", dbif) granu = cur_strds.get_granularity() start_time = tgis.datetime_math.check_datetime_string(extent[0]) start_gran = tgis.datetime_math.adjust_datetime_to_granularity( start_time, granu).isoformat() tempwhere += "(end_time > '{}' and start_time <= '{}')".format( start_gran, extent[1]) # needs to be set properly # Get info on registered maps in STRDS rows = cur_strds.get_registered_maps("name,mapset,start_time,end_time", tempwhere, "start_time", dbif) # Check temporal type and # define sampling function to use # becomes relevant when temporal type relative gets implemented if cur_strds.is_time_relative(): grass.fatal( _('Sorry, STRDS of relative temporal type is not (yet) supported' )) sample = sample_relative else: sample = sample_absolute # Check if there are raster maps to sample from that fullfill # temporal conditions if not rows and not tempwhere: dbif.close() grass.fatal( _("Space time raster dataset <%s> is empty".format( cur_strds.get_id()))) elif not rows and tempwhere: dbif.close() grass.fatal( _("No maps selected from Space time raster dataset <%s>, \ or dataset is empty".format(cur_strds.get_id()))) # Include temporal condition into where clause where_clause = '({}) AND '.format(where) if where else '' # Loop over registered maps in STRDS row_number = 0 for row in rows: # If r.what had a where option, r.what could be used to # collect raster values (without interpolation) # in a ParallelModuleQueue to collect values using multiple # cores and then upload results in one operation sample(input, layer, timestamp_column, column_names[counter], row, where_clause, i_flag) row_number += 1 grass.percent(row_number, len(rows), 3) counter = counter + 1 dbif.close() grass.vector_history(input)
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')
def main(): global tmp_graph, tmp_group, tmp_psmap, tmp_psleg, tmp_gisleg breakpoints = options['breakpoints'] colorscheme = options['colorscheme'] column = options['column'] endcolor = options['endcolor'] group = options['group'] layer = options['layer'] linecolor = options['linecolor'] map = options['map'] maxsize = options['maxsize'] monitor = options['monitor'] nint = options['nint'] pointcolor = options['pointcolor'] psmap = options['psmap'] size = options['size'] startcolor = options['startcolor'] themecalc = options['themecalc'] themetype = options['themetype'] type = options['type'] where = options['where'] icon = options['icon'] flag_f = flags['f'] flag_g = flags['g'] flag_l = flags['l'] flag_m = flags['m'] flag_s = flags['s'] flag_u = flags['u'] layer = int(layer) nint = int(nint) size = float(size) maxsize = float(maxsize) # check column type inf = grass.vector_columns(map, layer) if column not in inf: grass.fatal(_("No such column <%s>") % column) coltype = inf[column]['type'].lower() if coltype not in ["integer", "double precision"]: grass.fatal( _("Column <%s> is of type <%s> which is not numeric.") % (column, coltype)) # create temporary file to hold d.graph commands for legend tmp_graph = grass.tempfile() # Create temporary file to commands for GIS Manager group tmp_group = grass.tempfile() # Create temporary file for commands for ps.map map file tmp_psmap = grass.tempfile() # Create temporary file for commands for ps.map legend file tmp_psleg = grass.tempfile() # create file to hold elements for GIS Manager legend tmp_gisleg = grass.tempfile() # Set display variables for group atype = int(type == "area") ptype = int(type == "point") ctype = int(type == "centroid") ltype = int(type == "line") btype = int(type == "boundary") # if running in the GUI, do not create a graphic legend in an xmon if flag_s: flag_l = False # if running in GUI, turn off immediate mode rendering so that the # iterated d.vect commands will composite using the display driver os.environ['GRASS_PNG_READ'] = 'TRUE' os.environ['GRASS_PNG_AUTO_WRITE'] = 'FALSE' db = grass.vector_db(map)[1] if not db or not db['table']: grass.fatal( _("No table connected or layer <%s> does not exist.") % layer) table = db['table'] database = db['database'] driver = db['driver'] # update color values to the table? if flag_u: # test, if the column GRASSRGB is in the table s = grass.read_command('db.columns', table=table, database=database, driver=driver) if 'grassrgb' not in s.splitlines(): msg(locals(), _("Creating column 'grassrgb' in table <$table>")) sql = "ALTER TABLE %s ADD COLUMN grassrgb varchar(11)" % table grass.write_command('db.execute', database=database, driver=driver, stdin=sql) # Group name if not group: group = "themes" f_group = file(tmp_group, 'w') f_group.write("Group %s\n" % group) # Calculate statistics for thematic intervals if type == "line": stype = "line" else: stype = ["point", "centroid"] if not where: where = None stats = grass.read_command('v.univar', flags='eg', map=map, type=stype, column=column, where=where, layer=layer) stats = grass.parse_key_val(stats) min = float(stats['min']) max = float(stats['max']) mean = float(stats['mean']) sd = float(stats['population_stddev']) q1 = float(stats['first_quartile']) q2 = float(stats['median']) q3 = float(stats['third_quartile']) q4 = max ptsize = size if breakpoints and themecalc != "custom_breaks": grass.warning( _("Custom breakpoints ignored due to themecalc setting.")) # set interval for each thematic map calculation type if themecalc == "interval": numint = nint step = float(max - min) / numint breakpoints = [min + i * step for i in xrange(numint + 1)] annotations = "" elif themecalc == "std_deviation": # 2 standard deviation units on either side of mean, # plus min to -2 sd units and +2 sd units to max, if applicable breakpoints = [min] + [ i for i in [(mean + i * sd) for i in [-2, -1, 0, 1, 2]] if min < i < max ] + [max] annotations = [""] + [("%dsd" % i) for (i, j) in [(i, mean + i * sd) for i in [-2, -1, 0, 1, 2]] if (min < j < max)] + [""] annotations = ";".join(annotations) numint = len(breakpoints) - 1 elif themecalc == "quartiles": numint = 4 # one for each quartile breakpoints = [min, q1, q2, q3, max] annotations = " %f; %f; %f; %f" % (q1, q2, q3, q4) elif themecalc == "custom_breaks": if not breakpoints: breakpoints = sys.stdin.read() breakpoints = [int(x) for x in breakpoints.split()] numint = len(breakpoints) - 1 annotations = "" else: grass.fatal(_("Unknown themecalc type <%s>") % themecalc) pointstep = (maxsize - ptsize) / (numint - 1) # Prepare legend cuts for too large numint if numint > max_leg_items: xupper = int(numint - max_leg_items / 2) + 1 xlower = int(max_leg_items / 2) + 1 else: xupper = 0 xlower = 0 # legend title f_graph = file(tmp_graph, 'w') out( f_graph, locals(), """\ color 0:0:0 size 2 2 move 1 95 text Thematic map legend for column $column of map $map size 1.5 1.8 move 4 90 text Value range: $min - $max """) f_gisleg = file(tmp_gisleg, 'w') out( f_gisleg, locals(), """\ title - - - {Thematic map legend for column $column of map $map} """) f_psleg = file(tmp_psleg, 'w') out( f_psleg, locals(), """\ text 1% 95% Thematic map legend for column $column of map $map ref bottom left end text 4% 90% Value range: $min - $max ref bottom left end """) msg(locals(), _("Thematic map legend for column $column of map $map")) msg(locals(), _("Value range: $min - $max")) colorschemes = { "blue-red": ("0:0:255", "255:0:0"), "red-blue": ("255:0:0", "0:0:255"), "green-red": ("0:255:0", "255:0:0"), "red-green": ("255:0:0", "0:255:0"), "blue-green": ("0:0:255", "0:255:0"), "green-blue": ("0:255:0", "0:0:255"), "cyan-yellow": ("0:255:255", "255:255:0"), "yellow-cyan": ("255:255:0", "0:255:255"), "custom_gradient": (startcolor, endcolor) } # open file for psmap instructions f_psmap = file(tmp_psmap, 'w') # graduated color thematic mapping if themetype == "graduated_colors": if colorscheme in colorschemes: startc, endc = colorschemes[colorscheme] # set color schemes for graduated color maps elif colorscheme == "single_color": if themetype == "graduated_points": startc = endc = linecolor else: startc = endc = pointcolor else: grass.fatal( _("This should not happen: parser error. Unknown color scheme %s" ) % colorscheme) color = __builtins__.map(int, startc.split(":")) endcolor = __builtins__.map(int, endc.split(":")) #The number of color steps is one less then the number of classes nclrstep = numint - 1 clrstep = [(a - b) / nclrstep for a, b in zip(color, endcolor)] themecolor = startc # display graduated color themes if themecalc == "interval": out(f_graph, locals(), """\ move 4 87 text Mapped by $numint intervals of $step """) out( f_gisleg, locals(), """\ subtitle - - - {Mapped by $numint intervals of $step} """) out( f_psleg, locals(), """\ text 4% 87% Mapped by $numint intervals of $step ref bottom left end """) msg(locals(), _("Mapped by $numint intervals of $step")) # display graduated color themes for standard deviation units if themecalc == "std_deviation": out( f_graph, locals(), """\ move 4 87 text Mapped by standard deviation units of $sd (mean = $mean) """) out( f_gisleg, locals(), """\ subtitle - - - {Mapped by standard deviation units of $sd (mean = $mean)} """) out( f_psleg, locals(), """\ text 4% 87% Mapped by standard deviation units of $sd (mean = $mean) ref bottom left end """) msg(locals(), _("Mapped by standard deviation units of $sd (mean = $mean)")) # display graduated color themes for quartiles if themecalc == "quartiles": out(f_graph, locals(), """\ move 4 87 text Mapped by quartiles (median = $q2) """) out(f_gisleg, locals(), """\ subtitle - - - {Mapped by quartiles (median = $q2)} """) out( f_psleg, locals(), """\ text 4% 87% Mapped by quartiles (median = $q2) ref bottom left end """) msg(locals(), _("Mapped by quartiles (median = $q2)")) f_graph.write("""\ move 4 83 text Color move 14 83 text Value move 4 80 text ===== move 14 80 text ============ """) f_psleg.write("""\ text 4% 83% Color ref bottom left end text 14% 83% Value ref bottom left end text 4% 80% ===== ref bottom left end text 14% 80% ============ ref bottom left end """) sys.stdout.write("Color(R:G:B)\tValue\n") sys.stdout.write("============\t==========\n") line1 = 78 line2 = 76 line3 = 75 i = 1 first = True while i < numint: if flag_m: # math notation if first: closebracket = "]" openbracket = "[" mincomparison = ">=" first = False else: closebracket = "]" openbracket = "]" mincomparison = ">" else: closebracket = "" openbracket = "" if first: mincomparison = ">=" first = False else: mincomparison = ">" themecolor = ":".join(__builtins__.map(str, color)) if flag_f: linecolor = "none" else: if type in ["line", "boundary"]: linecolor = themecolor else: linecolor = linecolor rangemin = __builtins__.min(breakpoints) rangemax = __builtins__.max(breakpoints) if not annotations: extranote = "" else: extranote = annotations[i] if i < xlower or i >= xupper: xline1 = line2 + 2 xline3 = line2 - 1 out( f_graph, locals(), """\ color $themecolor polygon 5 $xline1 8 $xline1 8 $xline3 5 $xline3 color $linecolor move 5 $xline1 draw 8 $xline1 draw 8 $xline3 draw 5 $xline3 draw 5 $xline1 move 14 $line2 color 0:0:0 text $openbracket$rangemin - $rangemax$closebracket $extranote """) else: if i == xlower: out(f_graph, locals(), """\ color 0:0:0 move 10 $line2 text ... """) else: #undo next increment line2 += 4 if i < xlower or i >= xupper: out( f_gisleg, locals(), """\ area $themecolor $linecolor - {$openbracket$rangemin - $rangemax$closebracket $extranote} """) if type in ["line", "boundary"]: out( f_psleg, locals(), """\ line 5% $xline1% 8% $xline1% color $linecolor end text 14% $xline1% $openbracket$rangemin - $rangemax$closebracket $extranote ref center left end """) elif type in ["point", "centroid"]: out( f_psleg, locals(), """\ point 8% $xline1% color $linecolor fcolor $themecolor size $size symbol $icon end text 14% $xline1% $openbracket$rangemin - $rangemax$closebracket $extranote ref center left end """) else: out( f_psleg, locals(), """\ rectangle 5% $xline1% 8% $xline3% color 0:0:0 fcolor $themecolor end text 14% $xline3% $openbracket$rangemin - $rangemax$closebracket DCADCA $extranote ref bottom left end """) else: if i == xlower: out( f_psleg, locals(), """\ color 0:0:0 text 14% $xline3% ... ref bottom left end """) f_gisleg.write("text - - - {...}\n") sys.stdout.write( subs( locals(), "$themecolor\t\t$openbracket$rangemin - $rangemax$closebracket $extranote\n" )) if not where: sqlwhere = subs( locals(), "$column $mincomparison $rangemin AND $column <= $rangemax" ) else: sqlwhere = subs( locals(), "$column $mincomparison $rangemin AND $column <= $rangemax AND $where" ) # update color to database? if flag_u: sql = subs( locals(), "UPDATE $table SET GRASSRGB = '$themecolor' WHERE $sqlwhere" ) grass.write_command('db.execute', database=database, driver=driver, stdin=sql) # Create group for GIS Manager if flag_g: # change rgb colors to hex xthemecolor = "#%02X%02X%02X" % tuple( __builtins__.map(int, themecolor.split(":"))) #xlinecolor=`echo $linecolor | awk -F: '{printf("#%02X%02X%02X\n",$1,$2,$3)}'` if "$linecolor" == "black": xlinecolor = "#000000" else: xlinecolor = xthemecolor # create group entry out( f_group, locals(), """\ _check 1 Vector $column = $rangemin - $rangemax _check 1 map $map display_shape 1 display_cat 0 display_topo 0 display_dir 0 display_attr 0 type_point $ptype type_line $ltype type_boundary $btype type_centroid $ctype type_area $atype type_face 0 color $xlinecolor fcolor $xthemecolor width $ptsize _use_fcolor 1 lcolor #000000 sqlcolor 0 icon $icon size $ptsize field $layer lfield $layer attribute xref left yref center lsize 8 cat where $sqlwhere _query_text 0 _query_edit 1 _use_where 1 minreg maxreg _width 0.1 End """) # display theme vector map grass.run_command('d.vect', map=map, type=type, layer=layer, where=sqlwhere, color=linecolor, fcolor=themecolor, icon=icon, size=ptsize) if type in ["line", "boundary"]: out( f_psmap, locals(), """\ vlines $map type $type layer $layer where $sqlwhere color $linecolor label $rangemin - $rangemax end """) elif type in ["point", "centroid"]: out( f_psmap, locals(), """\ vpoints $map type $type layer $layer where $sqlwhere color $linecolor fcolor $themecolor symbol $icon label $rangemin - $rangemax end """) else: out( f_psmap, locals(), """\ vareas $map layer $layer where $sqlwhere color $linecolor fcolor $themecolor label $rangemin - $rangemax end """) # increment for next theme i += 1 if i == numint: color = endcolor else: color = [a - b for a, b in zip(color, clrstep)] line1 -= 4 line2 -= 4 line3 -= 4 #graduated points and line widths thematic mapping if themetype in ["graduated_points", "graduated_lines"]: #display graduated points/lines by intervals if themecalc == "interval": out(f_graph, locals(), """\ move 4 87 text Mapped by $numint intervals of $step """) out( f_gisleg, locals(), """\ subtitle - - - {Mapped by $numint intervals of $step} """) out( f_psleg, locals(), """\ text 4% 87% Mapped by $numint intervals of $step ref bottom left end """) msg(locals(), _("Mapped by $numint intervals of $step")) # display graduated points/lines for standard deviation units if themecalc == "std_deviation": out( f_graph, locals(), """\ move 4 87 text Mapped by standard deviation units of $sd (mean = $mean) """) out( f_gisleg, locals(), """\ subtitle - - - {Mapped by standard deviation units of $sd (mean = $mean)} """) out( f_psleg, locals(), """\ text 4% 87% Mapped by standard deviation units of $sd (mean = $mean) ref bottom left end """) msg(locals(), _("Mapped by standard deviation units of $sd (mean = $mean)")) # display graduated points/lines for quartiles if themecalc == "quartiles": out(f_graph, locals(), """\ move 4 87 text Mapped by quartiles (median = $q2) """) out(f_gisleg, locals(), """\ subtitle - - - {Mapped by quartiles (median = $q2)} """) out( f_psleg, locals(), """\ text 4% 87% Mapped by quartiles (median = $q2) ref bottom left end """) msg(locals(), _("Mapped by quartiles (median = $q2)")) line1 = 76 line2 = 75 out( f_graph, locals(), """\ move 4 83 text Size/width move 25 83 text Value move 4 80 text ============== move 25 80 text ============== """) out( f_psleg, locals(), """\ text 4% 83% Icon size ref bottom left end text 25% 83% Value ref bottom left end text 4% 80% ============ ref bottom left end text 25% 80% ============ ref bottom left end """) sys.stdout.write("Size/width\tValue\n") sys.stdout.write("==========\t=====\n") themecolor = pointcolor if flag_f: linecolor = "none" i = numint ptsize = maxsize while i >= 1: if flag_m: # math notation if i == 1: closebracket = "]" openbracket = "[" mincomparison = ">=" else: closebracket = "]" openbracket = "]" mincomparison = ">" else: closebracket = "" openbracket = "" if i == 1: mincomparison = ">=" else: mincomparison = ">" themecolor = pointcolor if flag_f: linecolor = "none" rangemin = __builtins__.min(breakpoints) rangemax = __builtins__.max(breakpoints) if not annotations: extranote = "" else: extranote = annotations[i] iconsize = int(ptsize / 2) lineht = int(ptsize / 4) if lineht < 4: lineht = 4 if i < xlower or i >= xupper: if themetype == "graduated_lines": out(f_graph, locals(), """\ color $linecolor """) out( f_gisleg, locals(), """\ line $themecolor $linecolor $ptsize {$openbracket$rangemin - $rangemax$closebracket $extranote} """) else: out(f_graph, locals(), """\ color $themecolor """) out( f_gisleg, locals(), """\ point $themecolor $linecolor $ptsize {$openbracket$rangemin - $rangemax$closebracket $extranote} """) out( f_graph, locals(), """\ icon + $iconsize 5 $line1 color 0:0:0 move 10 $line2 text $ptsize pts move 25 $line2 text $openbracket$rangemin - $rangemax$closebracket $extranote """) else: if i == xlower: out(f_graph, locals(), """\ color 0:0:0 move 10 $line2 text ... """) out(f_gisleg, locals(), """\ text - - - ... """) else: # undo future line increment line2 += lineht if i < xlower or i >= xupper: out( f_psleg, locals(), """\ point 8% $line1% color $linecolor fcolor $themecolor size $iconsize symbol $icon end text 25% $line1% $openbracket$rangemin - $rangemax$closebracket $extranote ref center left end """) else: if i == xlower: out(f_psleg, locals(), """\ text 25% $xline1% ... ref center left end """) sys.stdout.write( subs( locals(), "$ptsize\t\t$openbracket$rangemin - $rangemax$closebracket $extranote\n" )) if not where: sqlwhere = subs( locals(), "$column $mincomparison $rangemin AND $column <= $rangemax" ) else: sqlwhere = subs( locals(), "$column $mincomparison $rangemin AND $column <= $rangemax AND $where" ) # update color to database? if flag_u: sql = subs( locals(), "UPDATE $table SET grassrgb = '$themecolor' WHERE $sqlwhere" ) grass.write_command('db.execute', database=database, driver=driver, stdin=sql) # Create group for GIS Manager if flag_g: # change rgb colors to hex xthemecolor = "#%02X%02X%02X" % tuple( __builtins__.map(int, themecolor.split(":"))) xlinecolor = "#000000" # create group entry out( f_group, locals(), """\ _check 1 Vector $column = $rangemin - $rangemax _check 1 map $map display_shape 1 display_cat 0 display_topo 0 display_dir 0 display_attr 0 type_point $ptype type_line $ltype type_boundary $btype type_centroid $ctype type_area $atype type_face 0 color $xlinecolor width $ptsize fcolor $xthemecolor _use_fcolor 1 lcolor #000000 sqlcolor 0 icon $icon size $ptsize field $layer lfield $layer attribute xref left yref center lsize 8 cat where $sqlwhere _query_text 0 _query_edit 1 _use_where 1 minreg maxreg _width 0.1 End """) #graduates line widths or point sizes if themetype == "graduated_lines": grass.run_command('d.vect', map=map, type=type, layer=layer, where=sqlwhere, color=linecolor, fcolor=themecolor, icon=icon, size=ptsize, width=ptsize) else: grass.run_command('d.vect', map=map, type=type, layer=layer, where=sqlwhere, color=linecolor, fcolor=themecolor, icon=icon, size=ptsize) out( f_psmap, locals(), """\ vpoints $map type $type layer $layer where $sqlwhere color $linecolor fcolor $themecolor symbol $icon size $ptsize label $rangemin - $rangemax end """) ptsize -= pointstep line1 -= lineht line2 -= lineht i -= 1 # Create graphic legend f_graph.close() if flag_l: grass.run_command('d.erase') grass.run_command('d.graph', input=tmp_graph) # Create group file for GIS Manager f_group.write("End\n") f_group.close() if flag_g: shutil.copyfile(tmp_group, "%s.dm" % group) # Create ps.map map file f_psmap.write("end\n") f_psmap.close() if psmap: shutil.copyfile(tmp_psmap, "%s.psmap" % psmap) # Create ps.map legend file f_psleg.write("end\n") f_psleg.close() if psmap: shutil.copyfile(tmp_psleg, "%s_legend.psmap" % psmap) # Create text file to use with d.graph in GIS Manager f_gisleg.close() if flag_s: tmpdir = os.path.dirname(tmp_gisleg) tlegfile = os.path.join(tmpdir, "gismlegend.txt") shutil.copyfile(tmp_gisleg, tlegfile)
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")
def main(): global TMP_MAPS, vector, Land_cover, morpho_zones, distance_to, tile_size, id, population, area, built_up, output, png, nsres, ewres, lc_classes_list, morpho_classes_list TMP_MAPS = [] # user's values vector = options['vector'] Land_cover = options['land_cover'] morpho_zones = options['morpho_zones'] if options['morpho_zones'] else "" distance_to = options['distance_to'] if options['distance_to'] else "" tile_size = options['tile_size'] id = options['id'] population = options['population'] area = options['area'] built_up = options['built_up_category'] if options[ 'built_up_category'] else "" output = options['output'] png = options['png'] lc_list = options['lc_list'].split(",") if options['lc_list'] else "" morpho_list = options['morpho_list'].split( ",") if options['morpho_list'] else "" # vector exists? result = gscript.find_file(vector, element='vector') if len(result['name']) == 0: gscript.fatal(_("Input vector <%s> not found") % vector) # Land_cover exists? result = gscript.find_file(Land_cover, element='cell') if len(result['name']) == 0: gscript.fatal(_("Input Land Cover <%s> not found") % Land_cover) # id column exists ? if id not in gscript.vector_columns(vector).keys(): gscript.fatal( _("<%s> column does not exist for vector %s") % (id, vector)) # is id column numeric? coltype = gscript.vector_columns(vector)[id]['type'] if coltype not in ('INTEGER'): gscript.fatal(_("<%s> column must be Integer") % (id)) # population column exists ? if population not in gscript.vector_columns(vector).keys(): gscript.fatal( _("<%s> column does not exist for vector %s") % (population, vector)) # is population column numeric? coltype = gscript.vector_columns(vector)[population]['type'] if coltype not in ('INTEGER', 'DOUBLE PRECISION'): gscript.fatal(_("<%s> column must be numeric") % (population)) # area column exists ? if area not in gscript.vector_columns(vector).keys(): gscript.fatal( _("<%s> column does not exist for vector %s") % (area, vector)) # is area column numeric? coltype = gscript.vector_columns(vector)[area]['type'] if coltype not in ('INTEGER', 'DOUBLE PRECISION'): gscript.fatal(_("<%s> column must be numeric") % (area)) # is tile_size diffrent from null? if (int(tile_size) == 0): gscript.fatal(_("Tile size can't be NULL")) # morpho_zones exists? if (morpho_zones != ''): result = gscript.find_file(morpho_zones, element='cell') if (len(result['name']) == 0): gscript.fatal( _("Input morpho zones <%s> not found") % morpho_zones) # distance_to exists? if (distance_to != ''): result = gscript.find_file(distance_to, element='cell') if (len(result['name']) == 0): gscript.fatal(_("Input distance_to <%s> not found") % distance_to) # data preparation : extract classes and resolution from the Land Cover Data = Data_prep(Land_cover) nsres = Data[0] ## north-south resolution ewres = Data[1] ## east-west resolution if (lc_list == ""): lc_classes_list = Data[2] else: lc_classes_list = lc_list print(lc_classes_list) ## creating a gridded vector: each grid has a size of "tile_size" gscript.run_command('g.region', raster=Land_cover, res=tile_size) gscript.mapcalc("empty_grid=rand(0 ,999999999 )", overwrite=True, seed='auto') #creating a raster with random values gscript.run_command('r.clump', input='empty_grid', output='empty_grid_Clump', overwrite=True) #assigning a unique value to each grid gscript.run_command('r.to.vect', input='empty_grid_Clump', output='grid_vector', type='area', overwrite=True) #raster to vector admin_boundaries(vector.split("@")[0], id) ## calculating classes' proportions within each grid proportion_class_grid(Land_cover, 'grid_vector', lc_classes_list, "") ## calculating classes' proportions within each administrative unit proportion_class_admin(vector.split("@")[0], lc_classes_list, "") if (morpho_zones == ''): if (distance_to != ''): gscript.run_command('v.what.rast', map='grid_vector', type='centroid', raster=distance_to, column='distance') gscript.run_command('v.rast.stats', map=vector.split("@")[0] + '_rastTovect', raster=distance_to, column_prefix='distance', method='average', flags='c') else: if (distance_to != ''): gscript.run_command('v.what.rast', map='grid_vector', type='centroid', raster=distance_to, column='distance') gscript.run_command('v.rast.stats', map=vector.split("@")[0] + '_rastTovect', raster=distance_to, column_prefix='distance', method='average', flags='c') #Extract morpho layer's classes if (morpho_list == ""): morpho_classes_list = Data_prep(morpho_zones.split("@")[0])[2] else: morpho_classes_list = morpho_list #print(morpho_classes_list) # calculating classes' proportions within each grid proportion_class_grid( morpho_zones.split("@")[0], 'grid_vector', morpho_classes_list, "_morpho") # calculating classes' proportions within each administrative unit proportion_class_admin( vector.split("@")[0], morpho_classes_list, "_morpho") #RF RandomForest(vector.split("@")[0], id)
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')
def main(): color = options['color'] column = options['column'] layer = options['layer'] map = options['map'] range = options['range'] raster = options['raster'] rgb_column = options['rgb_column'] rules = options['rules'] flip = flags['n'] global tmp, tmp_colr, tmp_vcol pid = os.getpid() tmp = tmp_colr = tmp_vcol = None mapset = grass.gisenv()['MAPSET'] gisbase = os.getenv('GISBASE') # does map exist in CURRENT mapset? kv = grass.find_file(map, element = 'vector', mapset = mapset) if not kv['file']: grass.fatal(_("Vector map <%s> not found in current mapset") % map) vector = map.split('@', 1) # sanity check mutually exclusive color options if not options['color'] and not options['raster'] and not options['rules']: grass.fatal(_("Pick one of color, rules, or raster options")) if color: #### check the color rule is valid color_opts = os.listdir(os.path.join(gisbase, 'etc', 'colors')) color_opts += ['random', 'grey.eq', 'grey.log', 'rules'] if color not in color_opts: grass.fatal(_("Invalid color rule <%s>\n") % color + _("Valid options are: %s") % ' '.join(color_opts)) elif raster: if not grass.find_file(raster)['name']: grass.fatal(_("Raster raster map <%s> not found") % raster) elif rules: if not os.access(rules, os.R_OK): grass.fatal(_("Unable to read color rules file <%s>") % rules) # column checks # check input data column cols = grass.vector_columns(map, layer = layer) if column not in cols: grass.fatal(_("Column <%s> not found") % column) ncolumn_type = cols[column]['type'] if ncolumn_type not in ["INTEGER", "DOUBLE PRECISION"]: grass.fatal(_("Column <%s> is not numeric but %s") % (column, ncolumn_type)) # check if GRASSRGB column exists, make it if it doesn't table = grass.vector_db(map)[int(layer)]['table'] if rgb_column not in cols: # RGB Column not found, create it grass.message(_("Creating column <%s>...") % rgb_column) try: grass.run_command('v.db.addcolumn', map = map, layer = layer, column = "%s varchar(11)" % rgb_column) except CalledModuleError: grass.fatal(_("Creating color column")) else: column_type = cols[rgb_column]['type'] if column_type not in ["CHARACTER", "TEXT"]: grass.fatal(_("Column <%s> is not of compatible type (found %s)") % (rgb_column, column_type)) else: num_chars = dict([(v[0], int(v[2])) for v in grass.db_describe(table)['cols']])[rgb_column] if num_chars < 11: grass.fatal(_("Color column <%s> is not wide enough (needs 11 characters)"), rgb_column) cvals = grass.vector_db_select(map, layer = int(layer), columns = column)['values'].values() # find data range if range: # order doesn't matter vals = range.split(',') else: grass.message(_("Scanning values...")) vals = [float(x[0]) for x in cvals] minval = min(vals) maxval = max(vals) grass.verbose(_("Range: [%s, %s]") % (minval, maxval)) if minval is None or maxval is None: grass.fatal(_("Scanning data range")) # setup internal region grass.use_temp_region() grass.run_command('g.region', rows = 2, cols = 2) tmp_colr = "tmp_colr_%d" % pid # create dummy raster map if ncolumn_type == "INTEGER": grass.mapcalc("$tmp_colr = int(if(row() == 1, $minval, $maxval))", tmp_colr = tmp_colr, minval = minval, maxval = maxval) else: grass.mapcalc("$tmp_colr = double(if(row() == 1, $minval, $maxval))", tmp_colr = tmp_colr, minval = minval, maxval = maxval) if color: color_cmd = {'color': color} elif raster: color_cmd = {'raster': raster} elif rules: color_cmd = {'rules': rules} if flip: flip_flag = 'n' else: flip_flag = '' grass.run_command('r.colors', map = tmp_colr, flags = flip_flag, quiet = True, **color_cmd) tmp = grass.tempfile() # calculate colors and write SQL command file grass.message(_("Looking up colors...")) f = open(tmp, 'w') p = grass.feed_command('r.what.color', flags = 'i', input = tmp_colr, stdout = f) lastval = None for v in sorted(vals): if v == lastval: continue p.stdin.write('%f\n' % v) p.stdin.close() p.wait() f.close() tmp_vcol = "%s_vcol.sql" % tmp fi = open(tmp, 'r') fo = open(tmp_vcol, 'w') t = string.Template("UPDATE $table SET $rgb_column = '$colr' WHERE $column = $value;\n") found = 0 for line in fi: [value, colr] = line.split(': ') colr = colr.strip() if len(colr.split(':')) != 3: continue fo.write(t.substitute(table = table, rgb_column = rgb_column, colr = colr, column = column, value = value)) found += 1 fi.close() fo.close() if not found: grass.fatal(_("No values found in color range")) # apply SQL commands to update the table with values grass.message(_("Writing %s colors...") % found) try: grass.run_command('db.execute', input = tmp_vcol) except CalledModuleError: grass.fatal(_("Processing SQL transaction")) if flags['s']: vcolors = "vcolors_%d" % pid grass.run_command('g.rename', raster = (tmp_colr, vcolors), quiet = True) grass.message(_("Raster map containing color rules saved to <%s>") % vcolors) # TODO save full v.colors command line history grass.run_command('r.support', map = vcolors, history = "", source1 = "vector map = %s" % map, source2 = "column = %s" % column, title = _("Dummy raster to use as thematic vector legend"), description = "generated by v.colors using r.mapcalc") grass.run_command('r.support', map = vcolors, history = _("RGB saved into <%s> using <%s%s%s>") % (rgb_column, color, raster, rules))
def main(): global tmp_graph, tmp_group, tmp_psmap, tmp_psleg, tmp_gisleg breakpoints = options['breakpoints'] colorscheme = options['colorscheme'] column = options['column'] endcolor = options['endcolor'] group = options['group'] layer = options['layer'] linecolor = options['linecolor'] map = options['map'] maxsize = options['maxsize'] monitor = options['monitor'] nint = options['nint'] pointcolor = options['pointcolor'] psmap = options['psmap'] size = options['size'] startcolor = options['startcolor'] themecalc = options['themecalc'] themetype = options['themetype'] type = options['type'] where = options['where'] icon = options['icon'] flag_f = flags['f'] flag_g = flags['g'] flag_l = flags['l'] flag_m = flags['m'] flag_s = flags['s'] flag_u = flags['u'] layer = int(layer) nint = int(nint) size = float(size) maxsize = float(maxsize) # check column type inf = grass.vector_columns(map, layer) if column not in inf: grass.fatal(_("No such column <%s>") % column) coltype = inf[column]['type'].lower() if coltype not in ["integer", "double precision"]: grass.fatal(_("Column <%s> is of type <%s> which is not numeric.") % (column, coltype)) # create temporary file to hold d.graph commands for legend tmp_graph = grass.tempfile() # Create temporary file to commands for GIS Manager group tmp_group = grass.tempfile() # Create temporary file for commands for ps.map map file tmp_psmap = grass.tempfile() # Create temporary file for commands for ps.map legend file tmp_psleg = grass.tempfile() # create file to hold elements for GIS Manager legend tmp_gisleg = grass.tempfile() # Set display variables for group atype = int(type == "area") ptype = int(type == "point") ctype = int(type == "centroid") ltype = int(type == "line") btype = int(type == "boundary") # if running in the GUI, do not create a graphic legend in an xmon if flag_s: flag_l = False # if running in GUI, turn off immediate mode rendering so that the # iterated d.vect commands will composite using the display driver os.environ['GRASS_PNG_READ'] = 'TRUE' os.environ['GRASS_PNG_AUTO_WRITE'] = 'FALSE' db = grass.vector_db(map)[1] if not db or not db['table']: grass.fatal(_("No table connected or layer <%s> does not exist.") % layer) table = db['table'] database = db['database'] driver = db['driver'] # update color values to the table? if flag_u: # test, if the column GRASSRGB is in the table s = grass.read_command('db.columns', table = table, database = database, driver = driver) if 'grassrgb' not in s.splitlines(): msg(locals(), _("Creating column 'grassrgb' in table <$table>")) sql = "ALTER TABLE %s ADD COLUMN grassrgb varchar(11)" % table grass.write_command('db.execute', database = database, driver = driver, stdin = sql) # Group name if not group: group = "themes" f_group = file(tmp_group, 'w') f_group.write("Group %s\n" % group) # Calculate statistics for thematic intervals if type == "line": stype = "line" else: stype = ["point", "centroid"] if not where: where = None stats = grass.read_command('v.univar', flags = 'eg', map = map, type = stype, column = column, where = where, layer = layer) stats = grass.parse_key_val(stats) min = float(stats['min']) max = float(stats['max']) mean = float(stats['mean']) sd = float(stats['population_stddev']) q1 = float(stats['first_quartile']) q2 = float(stats['median']) q3 = float(stats['third_quartile']) q4 = max ptsize = size if breakpoints and themecalc != "custom_breaks": grass.warning(_("Custom breakpoints ignored due to themecalc setting.")) # set interval for each thematic map calculation type if themecalc == "interval": numint = nint step = float(max - min) / numint breakpoints = [min + i * step for i in xrange(numint + 1)] annotations = "" elif themecalc == "std_deviation": # 2 standard deviation units on either side of mean, # plus min to -2 sd units and +2 sd units to max, if applicable breakpoints = [min] + [i for i in [(mean + i * sd) for i in [-2,-1,0,1,2]] if min < i < max] + [max] annotations = [""] + [("%dsd" % i) for (i, j) in [(i, mean + i * sd) for i in [-2,-1,0,1,2]] if (min < j < max)] + [""] annotations = ";".join(annotations) numint = len(breakpoints) - 1 elif themecalc == "quartiles": numint=4 # one for each quartile breakpoints = [min, q1, q2, q3, max] annotations = " %f; %f; %f; %f" % (q1, q2, q3, q4) elif themecalc == "custom_breaks": if not breakpoints: breakpoints = sys.stdin.read() breakpoints = [int(x) for x in breakpoints.split()] numint = len(breakpoints) - 1 annotations = "" else: grass.fatal(_("Unknown themecalc type <%s>") % themecalc) pointstep = (maxsize - ptsize) / (numint - 1) # Prepare legend cuts for too large numint if numint > max_leg_items: xupper = int(numint - max_leg_items / 2) + 1 xlower = int(max_leg_items / 2) + 1 else: xupper = 0 xlower = 0 # legend title f_graph = file(tmp_graph, 'w') out(f_graph, locals(), """\ color 0:0:0 size 2 2 move 1 95 text Thematic map legend for column $column of map $map size 1.5 1.8 move 4 90 text Value range: $min - $max """) f_gisleg = file(tmp_gisleg, 'w') out(f_gisleg, locals(), """\ title - - - {Thematic map legend for column $column of map $map} """) f_psleg = file(tmp_psleg, 'w') out(f_psleg, locals(), """\ text 1% 95% Thematic map legend for column $column of map $map ref bottom left end text 4% 90% Value range: $min - $max ref bottom left end """) msg(locals(), _("Thematic map legend for column $column of map $map")) msg(locals(), _("Value range: $min - $max")) colorschemes = { "blue-red": ("0:0:255", "255:0:0"), "red-blue": ("255:0:0", "0:0:255"), "green-red": ("0:255:0", "255:0:0"), "red-green": ("255:0:0", "0:255:0"), "blue-green": ("0:0:255", "0:255:0"), "green-blue": ("0:255:0", "0:0:255"), "cyan-yellow": ("0:255:255", "255:255:0"), "yellow-cyan": ("255:255:0", "0:255:255"), "custom_gradient": (startcolor, endcolor) } # open file for psmap instructions f_psmap = file(tmp_psmap, 'w') # graduated color thematic mapping if themetype == "graduated_colors": if colorscheme in colorschemes: startc, endc = colorschemes[colorscheme] # set color schemes for graduated color maps elif colorscheme == "single_color": if themetype == "graduated_points": startc = endc = linecolor else: startc = endc = pointcolor else: grass.fatal(_("This should not happen: parser error. Unknown color scheme %s") % colorscheme) color = __builtins__.map(int, startc.split(":")) endcolor = __builtins__.map(int, endc.split(":")) #The number of color steps is one less then the number of classes nclrstep = numint - 1 clrstep = [(a - b) / nclrstep for a, b in zip(color, endcolor)] themecolor = startc # display graduated color themes if themecalc == "interval": out(f_graph, locals(), """\ move 4 87 text Mapped by $numint intervals of $step """) out(f_gisleg, locals(), """\ subtitle - - - {Mapped by $numint intervals of $step} """) out(f_psleg, locals(), """\ text 4% 87% Mapped by $numint intervals of $step ref bottom left end """) msg(locals(), _("Mapped by $numint intervals of $step")) # display graduated color themes for standard deviation units if themecalc == "std_deviation": out(f_graph, locals(), """\ move 4 87 text Mapped by standard deviation units of $sd (mean = $mean) """) out(f_gisleg, locals(), """\ subtitle - - - {Mapped by standard deviation units of $sd (mean = $mean)} """) out(f_psleg, locals(), """\ text 4% 87% Mapped by standard deviation units of $sd (mean = $mean) ref bottom left end """) msg(locals(), _("Mapped by standard deviation units of $sd (mean = $mean)")) # display graduated color themes for quartiles if themecalc == "quartiles": out(f_graph, locals(), """\ move 4 87 text Mapped by quartiles (median = $q2) """) out(f_gisleg, locals(), """\ subtitle - - - {Mapped by quartiles (median = $q2)} """) out(f_psleg, locals(), """\ text 4% 87% Mapped by quartiles (median = $q2) ref bottom left end """) msg(locals(), _("Mapped by quartiles (median = $q2)")) f_graph.write("""\ move 4 83 text Color move 14 83 text Value move 4 80 text ===== move 14 80 text ============ """) f_psleg.write("""\ text 4% 83% Color ref bottom left end text 14% 83% Value ref bottom left end text 4% 80% ===== ref bottom left end text 14% 80% ============ ref bottom left end """) sys.stdout.write("Color(R:G:B)\tValue\n") sys.stdout.write("============\t==========\n") line1 = 78 line2 = 76 line3 = 75 i = 1 first = True while i < numint: if flag_m: # math notation if first: closebracket = "]" openbracket = "[" mincomparison = ">=" first = False else: closebracket = "]" openbracket = "]" mincomparison = ">" else: closebracket = "" openbracket = "" if first: mincomparison = ">=" first = False else: mincomparison = ">" themecolor = ":".join(__builtins__.map(str,color)) if flag_f: linecolor = "none" else: if type in ["line", "boundary"]: linecolor = themecolor else: linecolor = linecolor rangemin = __builtins__.min(breakpoints) rangemax = __builtins__.max(breakpoints) if not annotations: extranote = "" else: extranote = annotations[i] if i < xlower or i >= xupper: xline1 = line2 + 2 xline3 = line2 - 1 out(f_graph, locals(), """\ color $themecolor polygon 5 $xline1 8 $xline1 8 $xline3 5 $xline3 color $linecolor move 5 $xline1 draw 8 $xline1 draw 8 $xline3 draw 5 $xline3 draw 5 $xline1 move 14 $line2 color 0:0:0 text $openbracket$rangemin - $rangemax$closebracket $extranote """) else: if i == xlower: out(f_graph, locals(), """\ color 0:0:0 move 10 $line2 text ... """) else: #undo next increment line2 += 4 if i < xlower or i >= xupper: out(f_gisleg, locals(), """\ area $themecolor $linecolor - {$openbracket$rangemin - $rangemax$closebracket $extranote} """) if type in ["line", "boundary"]: out(f_psleg, locals(), """\ line 5% $xline1% 8% $xline1% color $linecolor end text 14% $xline1% $openbracket$rangemin - $rangemax$closebracket $extranote ref center left end """) elif type in ["point", "centroid"]: out(f_psleg, locals(), """\ point 8% $xline1% color $linecolor fcolor $themecolor size $size symbol $icon end text 14% $xline1% $openbracket$rangemin - $rangemax$closebracket $extranote ref center left end """) else: out(f_psleg, locals(), """\ rectangle 5% $xline1% 8% $xline3% color 0:0:0 fcolor $themecolor end text 14% $xline3% $openbracket$rangemin - $rangemax$closebracket DCADCA $extranote ref bottom left end """) else: if i == xlower: out(f_psleg, locals(), """\ color 0:0:0 text 14% $xline3% ... ref bottom left end """) f_gisleg.write("text - - - {...}\n") sys.stdout.write(subs(locals(), "$themecolor\t\t$openbracket$rangemin - $rangemax$closebracket $extranote\n")) if not where: sqlwhere = subs(locals(), "$column $mincomparison $rangemin AND $column <= $rangemax") else: sqlwhere = subs(locals(), "$column $mincomparison $rangemin AND $column <= $rangemax AND $where") # update color to database? if flag_u: sql = subs(locals(), "UPDATE $table SET GRASSRGB = '$themecolor' WHERE $sqlwhere") grass.write_command('db.execute', database = database, driver = driver, stdin = sql) # Create group for GIS Manager if flag_g: # change rgb colors to hex xthemecolor = "#%02X%02X%02X" % tuple(__builtins__.map(int, themecolor.split(":"))) #xlinecolor=`echo $linecolor | awk -F: '{printf("#%02X%02X%02X\n",$1,$2,$3)}'` if "$linecolor" == "black": xlinecolor = "#000000" else: xlinecolor = xthemecolor # create group entry out(f_group, locals(), """\ _check 1 Vector $column = $rangemin - $rangemax _check 1 map $map display_shape 1 display_cat 0 display_topo 0 display_dir 0 display_attr 0 type_point $ptype type_line $ltype type_boundary $btype type_centroid $ctype type_area $atype type_face 0 color $xlinecolor fcolor $xthemecolor width $ptsize _use_fcolor 1 lcolor #000000 sqlcolor 0 icon $icon size $ptsize field $layer lfield $layer attribute xref left yref center lsize 8 cat where $sqlwhere _query_text 0 _query_edit 1 _use_where 1 minreg maxreg _width 0.1 End """) # display theme vector map grass.run_command('d.vect', map = map, type = type, layer = layer, where = sqlwhere, color = linecolor, fcolor = themecolor, icon = icon, size = ptsize) if type in ["line", "boundary"]: out(f_psmap, locals(), """\ vlines $map type $type layer $layer where $sqlwhere color $linecolor label $rangemin - $rangemax end """) elif type in ["point", "centroid"]: out(f_psmap, locals(), """\ vpoints $map type $type layer $layer where $sqlwhere color $linecolor fcolor $themecolor symbol $icon label $rangemin - $rangemax end """) else: out(f_psmap, locals(), """\ vareas $map layer $layer where $sqlwhere color $linecolor fcolor $themecolor label $rangemin - $rangemax end """) # increment for next theme i += 1 if i == numint: color = endcolor else: color = [a - b for a, b in zip(color, clrstep)] line1 -= 4 line2 -= 4 line3 -= 4 #graduated points and line widths thematic mapping if themetype in ["graduated_points", "graduated_lines"]: #display graduated points/lines by intervals if themecalc == "interval": out(f_graph, locals(), """\ move 4 87 text Mapped by $numint intervals of $step """) out(f_gisleg, locals(), """\ subtitle - - - {Mapped by $numint intervals of $step} """) out(f_psleg, locals(), """\ text 4% 87% Mapped by $numint intervals of $step ref bottom left end """) msg(locals(), _("Mapped by $numint intervals of $step")) # display graduated points/lines for standard deviation units if themecalc == "std_deviation": out(f_graph, locals(), """\ move 4 87 text Mapped by standard deviation units of $sd (mean = $mean) """) out(f_gisleg, locals(), """\ subtitle - - - {Mapped by standard deviation units of $sd (mean = $mean)} """) out(f_psleg, locals(), """\ text 4% 87% Mapped by standard deviation units of $sd (mean = $mean) ref bottom left end """) msg(locals(), _("Mapped by standard deviation units of $sd (mean = $mean)")) # display graduated points/lines for quartiles if themecalc == "quartiles": out(f_graph, locals(), """\ move 4 87 text Mapped by quartiles (median = $q2) """) out(f_gisleg, locals(), """\ subtitle - - - {Mapped by quartiles (median = $q2)} """) out(f_psleg, locals(), """\ text 4% 87% Mapped by quartiles (median = $q2) ref bottom left end """) msg(locals(), _("Mapped by quartiles (median = $q2)")) line1 = 76 line2 = 75 out(f_graph, locals(), """\ move 4 83 text Size/width move 25 83 text Value move 4 80 text ============== move 25 80 text ============== """) out(f_psleg, locals(), """\ text 4% 83% Icon size ref bottom left end text 25% 83% Value ref bottom left end text 4% 80% ============ ref bottom left end text 25% 80% ============ ref bottom left end """) sys.stdout.write("Size/width\tValue\n") sys.stdout.write("==========\t=====\n") themecolor = pointcolor if flag_f: linecolor = "none" i = numint ptsize = maxsize while i >= 1: if flag_m: # math notation if i == 1: closebracket = "]" openbracket = "[" mincomparison = ">=" else: closebracket = "]" openbracket = "]" mincomparison = ">" else: closebracket = "" openbracket = "" if i == 1: mincomparison = ">=" else: mincomparison = ">" themecolor = pointcolor if flag_f: linecolor = "none" rangemin = __builtins__.min(breakpoints) rangemax = __builtins__.max(breakpoints) if not annotations: extranote = "" else: extranote = annotations[i] iconsize = int(ptsize / 2) lineht = int(ptsize / 4) if lineht < 4: lineht = 4 if i < xlower or i >= xupper: if themetype == "graduated_lines": out(f_graph, locals(), """\ color $linecolor """) out(f_gisleg, locals(), """\ line $themecolor $linecolor $ptsize {$openbracket$rangemin - $rangemax$closebracket $extranote} """) else: out(f_graph, locals(), """\ color $themecolor """) out(f_gisleg, locals(), """\ point $themecolor $linecolor $ptsize {$openbracket$rangemin - $rangemax$closebracket $extranote} """) out(f_graph, locals(), """\ icon + $iconsize 5 $line1 color 0:0:0 move 10 $line2 text $ptsize pts move 25 $line2 text $openbracket$rangemin - $rangemax$closebracket $extranote """) else: if i == xlower: out(f_graph, locals(), """\ color 0:0:0 move 10 $line2 text ... """) out(f_gisleg, locals(), """\ text - - - ... """) else: # undo future line increment line2 += lineht if i < xlower or i >= xupper: out(f_psleg, locals(), """\ point 8% $line1% color $linecolor fcolor $themecolor size $iconsize symbol $icon end text 25% $line1% $openbracket$rangemin - $rangemax$closebracket $extranote ref center left end """) else: if i == xlower: out(f_psleg, locals(), """\ text 25% $xline1% ... ref center left end """) sys.stdout.write(subs(locals(), "$ptsize\t\t$openbracket$rangemin - $rangemax$closebracket $extranote\n")) if not where: sqlwhere = subs(locals(), "$column $mincomparison $rangemin AND $column <= $rangemax") else: sqlwhere = subs(locals(), "$column $mincomparison $rangemin AND $column <= $rangemax AND $where") # update color to database? if flag_u: sql = subs(locals(), "UPDATE $table SET grassrgb = '$themecolor' WHERE $sqlwhere") grass.write_command('db.execute', database = database, driver = driver, stdin = sql) # Create group for GIS Manager if flag_g: # change rgb colors to hex xthemecolor = "#%02X%02X%02X" % tuple(__builtins__.map(int,themecolor.split(":"))) xlinecolor = "#000000" # create group entry out(f_group, locals(), """\ _check 1 Vector $column = $rangemin - $rangemax _check 1 map $map display_shape 1 display_cat 0 display_topo 0 display_dir 0 display_attr 0 type_point $ptype type_line $ltype type_boundary $btype type_centroid $ctype type_area $atype type_face 0 color $xlinecolor width $ptsize fcolor $xthemecolor _use_fcolor 1 lcolor #000000 sqlcolor 0 icon $icon size $ptsize field $layer lfield $layer attribute xref left yref center lsize 8 cat where $sqlwhere _query_text 0 _query_edit 1 _use_where 1 minreg maxreg _width 0.1 End """) #graduates line widths or point sizes if themetype == "graduated_lines": grass.run_command('d.vect', map = map, type = type, layer = layer, where = sqlwhere, color = linecolor, fcolor = themecolor, icon = icon, size = ptsize, width = ptsize) else: grass.run_command('d.vect', map = map, type = type, layer = layer, where = sqlwhere, color = linecolor, fcolor = themecolor, icon = icon, size = ptsize) out(f_psmap, locals(), """\ vpoints $map type $type layer $layer where $sqlwhere color $linecolor fcolor $themecolor symbol $icon size $ptsize label $rangemin - $rangemax end """) ptsize -= pointstep line1 -= lineht line2 -= lineht i -= 1 # Create graphic legend f_graph.close() if flag_l: grass.run_command('d.erase') grass.run_command('d.graph', input = tmp_graph) # Create group file for GIS Manager f_group.write("End\n") f_group.close() if flag_g: shutil.copyfile(tmp_group, "%s.dm" % group) # Create ps.map map file f_psmap.write("end\n") f_psmap.close() if psmap: shutil.copyfile(tmp_psmap, "%s.psmap" % psmap) # Create ps.map legend file f_psleg.write("end\n") f_psleg.close() if psmap: shutil.copyfile(tmp_psleg, "%s_legend.psmap" % psmap) # Create text file to use with d.graph in GIS Manager f_gisleg.close() if flag_s: tmpdir = os.path.dirname(tmp_gisleg) tlegfile = os.path.join(tmpdir, "gismlegend.txt") shutil.copyfile(tmp_gisleg, tlegfile)
def main(): map = options["map"] layer = options["layer"] column = options["column"] otable = options["other_table"] ocolumn = options["other_column"] if options["subset_columns"]: scolumns = options["subset_columns"].split(",") else: scolumns = None try: f = grass.vector_layer_db(map, layer) except CalledModuleError: sys.exit(1) maptable = f["table"] database = f["database"] driver = f["driver"] if driver == "dbf": grass.fatal(_("JOIN is not supported for tables stored in DBF format")) if not maptable: grass.fatal( _("There is no table connected to this map. Unable to join any column." )) # check if column is in map table if column not in grass.vector_columns(map, layer): grass.fatal( _("Column <%s> not found in table <%s>") % (column, maptable)) # describe other table all_cols_ot = grass.db_describe(otable, driver=driver, database=database)["cols"] # check if ocolumn is on other table if ocolumn not in [ocol[0] for ocol in all_cols_ot]: grass.fatal( _("Column <%s> not found in table <%s>") % (ocolumn, otable)) # determine columns subset from other table if not scolumns: # select all columns from other table cols_to_add = all_cols_ot else: cols_to_add = [] # check if scolumns exists in the other table for scol in scolumns: found = False for col_ot in all_cols_ot: if scol == col_ot[0]: found = True cols_to_add.append(col_ot) break if not found: grass.warning( _("Column <%s> not found in table <%s>") % (scol, otable)) all_cols_tt = grass.vector_columns(map, int(layer)).keys() select = "SELECT $colname FROM $otable WHERE $otable.$ocolumn=$table.$column" template = string.Template("UPDATE $table SET $colname=(%s);" % select) for col in cols_to_add: # skip the vector column which is used for join colname = col[0] if colname == column: continue use_len = False if len(col) > 2: use_len = True # Sqlite 3 does not support the precision number any more if driver == "sqlite": use_len = False # MySQL - expect format DOUBLE PRECISION(M,D), see #2792 elif driver == "mysql" and col[1] == "DOUBLE PRECISION": use_len = False if use_len: coltype = "%s(%s)" % (col[1], col[2]) else: coltype = "%s" % col[1] colspec = "%s %s" % (colname, coltype) # add only the new column to the table if colname not in all_cols_tt: try: grass.run_command("v.db.addcolumn", map=map, columns=colspec, layer=layer) except CalledModuleError: grass.fatal(_("Error creating column <%s>") % colname) stmt = template.substitute( table=maptable, column=column, otable=otable, ocolumn=ocolumn, colname=colname, ) grass.debug(stmt, 1) grass.verbose( _("Updating column <%s> of vector map <%s>...") % (colname, map)) try: grass.write_command("db.execute", stdin=stmt, input="-", database=database, driver=driver) except CalledModuleError: grass.fatal(_("Error filling column <%s>") % colname) # write cmd history grass.vector_history(map) return 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)