v.report.py 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. #!/usr/bin/env python
  2. #
  3. ############################################################################
  4. #
  5. # MODULE: v.report
  6. # AUTHOR(S): Markus Neteler, converted to Python by Glynn Clements
  7. # PURPOSE: Reports geometry statistics for vector maps
  8. # COPYRIGHT: (C) 2005, 2007-2009 by MN and the GRASS Development Team
  9. #
  10. # This program is free software under the GNU General Public
  11. # License (>=v2). Read the file COPYING that comes with GRASS
  12. # for details.
  13. #
  14. #############################################################################
  15. #%Module
  16. #% description: Reports geometry statistics for vector maps.
  17. #% keywords: vector
  18. #% keywords: geometry
  19. #% keywords: statistics
  20. #%End
  21. #%Flag
  22. #% key: r
  23. #% description: Reverse sort the result
  24. #%End
  25. #%Flag
  26. #% key: s
  27. #% description: Sort the result
  28. #%End
  29. #%option
  30. #% key: map
  31. #% type: string
  32. #% gisprompt: old,vector,vector
  33. #% label: Name of input vector map
  34. #% description: Data source for OGR access
  35. #% required: yes
  36. #%end
  37. #%option
  38. #% key: layer
  39. #% type: string
  40. #% answer: 1
  41. #% label: Layer number or name
  42. #% description: A single vector map can be connected to multiple database tables. This number determines which table to use. Layer name for OGR access.
  43. #% gisprompt: old_layer,layer,layer
  44. #% required: no
  45. #%end
  46. #%option
  47. #% key: option
  48. #% type: string
  49. #% description: Value to calculate
  50. #% options: area,length,coor
  51. #% required: yes
  52. #%end
  53. #%option
  54. #% key: units
  55. #% type: string
  56. #% description: Units
  57. #% options: miles,feet,meters,kilometers,acres,hectares,percent
  58. #% required: no
  59. #%end
  60. import sys
  61. import os
  62. import grass.script as grass
  63. def uniq(l):
  64. result = []
  65. last = None
  66. for i in l:
  67. if i != last:
  68. result.append(i)
  69. last = i
  70. return result
  71. def main():
  72. if flags['r'] and flags['s']:
  73. grass.fatal(_("Either -r or -s flag"))
  74. mapname = options['map']
  75. option = options['option']
  76. layer = options['layer']
  77. units = options['units']
  78. nuldev = file(os.devnull, 'w')
  79. if not grass.find_file(mapname, 'vector')['file']:
  80. grass.fatal(_("Vector map '%s' not found in mapset search path.") % mapname)
  81. colnames = grass.vector_columns(mapname, layer, getDict = False, stderr = nuldev)
  82. if not colnames:
  83. colnames = ['cat']
  84. if option == 'coor':
  85. columns = ['dummy1','dummy2','dummy3']
  86. extracolnames = ['x','y','z']
  87. else:
  88. columns = ['dummy1']
  89. extracolnames = [option]
  90. if units in ['p','percent']:
  91. unitsp = 'meters'
  92. elif units:
  93. unitsp = units
  94. else:
  95. unitsp = None
  96. # NOTE: we suppress -1 cat and 0 cat
  97. if colnames:
  98. p = grass.pipe_command('v.db.select', quiet = True, flags='c', map = mapname, layer = layer)
  99. records1 = []
  100. for line in p.stdout:
  101. cols = line.rstrip('\r\n').split('|')
  102. if cols[0] == '0':
  103. continue
  104. records1.append([int(cols[0])] + cols[1:])
  105. p.wait()
  106. if p.returncode != 0:
  107. sys.exit(1)
  108. records1.sort()
  109. if len(records1) == 0:
  110. try:
  111. f = grass.vector_db(map = mapname)[int(layer)]
  112. grass.fatal(_("There is a table connected to input vector map '%s', but"
  113. "there are no categories present in the key column '%s'. Consider using"
  114. "v.to.db to correct this.") % (mapname, f['key']))
  115. except KeyError:
  116. pass
  117. #fetch the requested attribute sorted by cat:
  118. p = grass.pipe_command('v.to.db', flags = 'p',
  119. quiet = True,
  120. map = mapname, option = option, columns = columns,
  121. layer = layer, units = unitsp)
  122. records2 = []
  123. for line in p.stdout:
  124. fields = line.rstrip('\r\n').split('|')
  125. if fields[0] in ['cat', '-1', '0']:
  126. continue
  127. records2.append([int(fields[0])] + fields[1:])
  128. p.wait()
  129. records2.sort()
  130. #make pre-table
  131. records3 = [r1 + r2[1:] for r1, r2 in zip(records1, records2)]
  132. else:
  133. records1 = []
  134. p = grass.pipe_command('v.category', inp = mapname, layer = layer, option = 'print')
  135. for line in p.stdout:
  136. field = int(line.rstrip())
  137. if field > 0:
  138. records1.append(field)
  139. p.wait()
  140. records1.sort()
  141. records1 = uniq(records1)
  142. #make pre-table
  143. p = grass.pipe_command('v.to.db', flags = 'p',
  144. map = mapname, option = option, columns = columns,
  145. layer = layer, units = unitsp)
  146. records3 = []
  147. for line in p.stdout:
  148. fields = line.split('|')
  149. if fields[0] in ['cat', '-1', '0']:
  150. continue
  151. records3.append([int(fields[0])] + fields[1:])
  152. p.wait()
  153. records3.sort()
  154. # print table header
  155. sys.stdout.write('|'.join(colnames + extracolnames) + '\n')
  156. #make and print the table:
  157. numcols = len(colnames) + len(extracolnames)
  158. # calculate percents if requested
  159. if units != '' and units in ['p','percent']:
  160. # calculate total area value
  161. areatot = 0
  162. for r in records3:
  163. areatot += float(r[-1])
  164. # calculate area percentages
  165. records4 = [float(r[-1]) * 100 / areatot for r in records3]
  166. records3 = [r1 + [r4] for r1, r4 in zip(records1, records4)]
  167. if flags['s']:
  168. # sort
  169. records3.sort(key = lambda r: (r[0], r[-1]))
  170. elif flags['r']:
  171. # reverse sort
  172. records3.sort(key = lambda r: (r[0], r[-1]), reverse = True)
  173. for r in records3:
  174. sys.stdout.write('|'.join(map(str,r)) + '\n')
  175. if __name__ == "__main__":
  176. options, flags = grass.parser()
  177. main()