v.report.py 5.7 KB

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