|
@@ -0,0 +1,208 @@
|
|
|
|
+#!/usr/bin/env python
|
|
|
|
+#
|
|
|
|
+############################################################################
|
|
|
|
+#
|
|
|
|
+# MODULE: v.report
|
|
|
|
+# AUTHOR(S): Markus Neteler, converted to Python by Glynn Clements
|
|
|
|
+# PURPOSE: Reports geometry statistics for vector maps
|
|
|
|
+# COPYRIGHT: (C) 2005, 2007 by MN and the GRASS Development Team
|
|
|
|
+#
|
|
|
|
+# This program is free software under the GNU General Public
|
|
|
|
+# License (>=v2). Read the file COPYING that comes with GRASS
|
|
|
|
+# for details.
|
|
|
|
+#
|
|
|
|
+#############################################################################
|
|
|
|
+
|
|
|
|
+#%Module
|
|
|
|
+#% description: Reports geometry statistics for vectors.
|
|
|
|
+#% keywords: vector, report, statistics
|
|
|
|
+#%End
|
|
|
|
+#%Flag
|
|
|
|
+#% key: r
|
|
|
|
+#% description: Reverse sort the result
|
|
|
|
+#%End
|
|
|
|
+#%Flag
|
|
|
|
+#% key: s
|
|
|
|
+#% description: Sort the result
|
|
|
|
+#%End
|
|
|
|
+#%option
|
|
|
|
+#% key: map
|
|
|
|
+#% type: string
|
|
|
|
+#% gisprompt: old,vector,vector
|
|
|
|
+#% description: Name of input vector map
|
|
|
|
+#% required: yes
|
|
|
|
+#%end
|
|
|
|
+#%option
|
|
|
|
+#% key: layer
|
|
|
|
+#% type: integer
|
|
|
|
+#% answer: 1
|
|
|
|
+#% description: Layer number
|
|
|
|
+#% required: no
|
|
|
|
+#%end
|
|
|
|
+#%option
|
|
|
|
+#% key: option
|
|
|
|
+#% type: string
|
|
|
|
+#% description: Value to calculate
|
|
|
|
+#% options: area,length,coor
|
|
|
|
+#% required: yes
|
|
|
|
+#%end
|
|
|
|
+#%option
|
|
|
|
+#% key: units
|
|
|
|
+#% type: string
|
|
|
|
+#% description: mi(les),f(eet),me(ters),k(ilometers),a(cres),h(ectares),p(ercent)
|
|
|
|
+#% options: mi,miles,f,feet,me,meters,k,kilometers,a,acres,h,hectares,p,percent
|
|
|
|
+#% required: no
|
|
|
|
+#%end
|
|
|
|
+
|
|
|
|
+import sys
|
|
|
|
+import os
|
|
|
|
+import grass
|
|
|
|
+
|
|
|
|
+def find_key(map, layer):
|
|
|
|
+ s = grass.read_command('v.db.connect', flags = 'g', map = map);
|
|
|
|
+ for line in s.splitlines():
|
|
|
|
+ fields = line.split()
|
|
|
|
+ if fields[0] == layer:
|
|
|
|
+ return fields[3]
|
|
|
|
+ return '<unknown>'
|
|
|
|
+
|
|
|
|
+def uniq(l):
|
|
|
|
+ result = []
|
|
|
|
+ last = None
|
|
|
|
+ for i in l:
|
|
|
|
+ if i != last:
|
|
|
|
+ result.append(i)
|
|
|
|
+ last = i
|
|
|
|
+ return result
|
|
|
|
+
|
|
|
|
+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)
|
|
|
|
+
|
|
|
|
+ table_exists = grass.run_command('v.info', flags = 'c', map = mapname,
|
|
|
|
+ layer = layer, stdout = nuldev,
|
|
|
|
+ stderr = nuldev) == 0
|
|
|
|
+
|
|
|
|
+ if table_exists:
|
|
|
|
+ p = grass.pipe_command('v.info', flags = 'c', map = mapname, layer = layer, stderr = nuldev)
|
|
|
|
+ colnames = []
|
|
|
|
+ for line in p.stdout:
|
|
|
|
+ if '|' not in line:
|
|
|
|
+ continue
|
|
|
|
+ colnames.append(line.rstrip('\r\n').split('|')[1])
|
|
|
|
+ p.wait()
|
|
|
|
+ else:
|
|
|
|
+ colnames = ['cat']
|
|
|
|
+
|
|
|
|
+ if option == 'coor':
|
|
|
|
+ columns = ['dummy1','dummy2','dummy3']
|
|
|
|
+ extracolnames = ['x','y','z']
|
|
|
|
+ else:
|
|
|
|
+ columns = ['dummy1']
|
|
|
|
+ extracolnames = [option]
|
|
|
|
+
|
|
|
|
+ if units in ['p','percent']:
|
|
|
|
+ unitsp = {'units': 'meters'}
|
|
|
|
+ elif units:
|
|
|
|
+ unitsp = {'units': 'meters'}
|
|
|
|
+ else:
|
|
|
|
+ unitsp = {}
|
|
|
|
+
|
|
|
|
+ # NOTE: we suppress -1 cat and 0 cat
|
|
|
|
+
|
|
|
|
+ if table_exists:
|
|
|
|
+ p = grass.pipe_command('v.db.select', 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()
|
|
|
|
+ records1.sort()
|
|
|
|
+
|
|
|
|
+ if len(records1) == 0:
|
|
|
|
+ key = find_key(mapname, 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, key))
|
|
|
|
+
|
|
|
|
+ #fetch the requested attribute sorted by cat:
|
|
|
|
+ p = grass.pipe_command('v.to.db', flags = 'p',
|
|
|
|
+ map = mapname, option = option, columns = columns,
|
|
|
|
+ layer = layer, **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, **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')
|
|
|
|
+
|
|
|
|
+if __name__ == "__main__":
|
|
|
|
+ options, flags = grass.parser()
|
|
|
|
+ main()
|