vector.py 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328
  1. """!@package grass.script.vector
  2. @brief GRASS Python scripting module (vector functions)
  3. Vector related functions to be used in Python scripts.
  4. Usage:
  5. @code
  6. from grass.script import vector as grass
  7. grass.vector_db(map)
  8. ...
  9. @endcode
  10. (C) 2008-2010 by the GRASS Development Team
  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. @author Glynn Clements
  15. @author Martin Landa <landa.martin gmail.com>
  16. """
  17. import os
  18. import types
  19. import __builtin__
  20. from core import *
  21. # i18N
  22. import gettext
  23. gettext.install('grasslibs', os.path.join(os.getenv("GISBASE"), 'locale'), unicode=True)
  24. # run "v.db.connect -g ..." and parse output
  25. def vector_db(map, **args):
  26. """!Return the database connection details for a vector map
  27. (interface to `v.db.connect -g'). Example:
  28. \code
  29. >>> grass.vector_db('lakes')
  30. {1: {'layer': '1', 'name': '',
  31. 'database': '/home/martin/grassdata/nc_spm_08/PERMANENT/dbf/',
  32. 'driver': 'dbf', 'key': 'cat', 'table': 'lakes'}}
  33. \endcode
  34. @param map vector map
  35. @param args
  36. @return dictionary { layer : { 'layer', 'table, 'database', 'driver', 'key' }
  37. """
  38. s = read_command('v.db.connect', flags = 'g', map = map, fs = ';', **args)
  39. result = {}
  40. for l in s.splitlines():
  41. f = l.split(';')
  42. if len(f) != 5:
  43. continue
  44. if '/' in f[0]:
  45. f1 = f[0].split('/')
  46. layer = f1[0]
  47. name = f1[1]
  48. else:
  49. layer = f[0]
  50. name = ''
  51. result[int(layer)] = {
  52. 'layer' : layer,
  53. 'name' : name,
  54. 'table' : f[1],
  55. 'key' : f[2],
  56. 'database' : f[3],
  57. 'driver' : f[4] }
  58. return result
  59. def vector_layer_db(map, layer):
  60. """!Return the database connection details for a vector map layer.
  61. If db connection for given layer is not defined, fatal() is called.
  62. @param map map name
  63. @param layer layer number
  64. @return parsed output
  65. """
  66. try:
  67. f = vector_db(map)[int(layer)]
  68. except KeyError:
  69. fatal(_("Database connection not defined for layer %s") % layer)
  70. return f
  71. # run "v.info -c ..." and parse output
  72. def vector_columns(map, layer = None, getDict = True, **args):
  73. """!Return a dictionary (or a list) of the columns for the
  74. database table connected to a vector map (interface to `v.info
  75. -c').
  76. @code
  77. >>> vector_columns(urbanarea, getDict = True)
  78. {'UA_TYPE': {'index': 4, 'type': 'CHARACTER'}, 'UA': {'index': 2, 'type': 'CHARACTER'}, 'NAME': {'index': 3, 'type': 'CHARACTER'}, 'OBJECTID': {'index': 1, 'type': 'INTEGER'}, 'cat': {'index': 0, 'type': 'INTEGER'}}
  79. >>> vector_columns(urbanarea, getDict = False)
  80. ['cat', 'OBJECTID', 'UA', 'NAME', 'UA_TYPE']
  81. @endcode
  82. @param map map name
  83. @param layer layer number or name (None for all layers)
  84. @param getDict True to return dictionary of columns otherwise list of column names is returned
  85. @param args (v.info's arguments)
  86. @return dictionary/list of columns
  87. """
  88. s = read_command('v.info', flags = 'c', map = map, layer = layer, quiet = True, **args)
  89. if getDict:
  90. result = dict()
  91. else:
  92. result = list()
  93. i = 0
  94. for line in s.splitlines():
  95. ctype, cname = line.split('|')
  96. if getDict:
  97. result[cname] = { 'type' : ctype,
  98. 'index' : i }
  99. else:
  100. result.append(cname)
  101. i+=1
  102. return result
  103. # add vector history
  104. def vector_history(map):
  105. """!Set the command history for a vector map to the command used to
  106. invoke the script (interface to `v.support').
  107. @param map mapname
  108. @return v.support output
  109. """
  110. run_command('v.support', map = map, cmdhist = os.environ['CMDLINE'])
  111. # run "v.info -t" and parse output
  112. def vector_info_topo(map):
  113. """!Return information about a vector map (interface to `v.info
  114. -t'). Example:
  115. \code
  116. >>> grass.vector_info_topo('lakes')
  117. {'kernels': 0, 'lines': 0, 'centroids': 15279,
  118. 'boundaries': 27764, 'points': 0, 'faces': 0,
  119. 'primitives': 43043, 'islands': 7470, 'nodes': 35234, 'map3d': False, 'areas': 15279}
  120. \endcode
  121. @param map map name
  122. @return parsed output
  123. """
  124. s = read_command('v.info', flags = 't', map = map)
  125. ret = parse_key_val(s, val_type = int)
  126. if ret.has_key('map3d'):
  127. ret['map3d'] = bool(ret['map3d'])
  128. return ret
  129. # interface for v.db.select
  130. def vector_db_select(map, layer = 1, **kwargs):
  131. """!Get attribute data of selected vector map layer.
  132. Function returns list of columns and dictionary of values ordered by
  133. key column value. Example:
  134. \code
  135. >>> print grass.vector_select('lakes')['values'][3]
  136. ['3', '19512.86146', '708.44683', '4', '55652', 'LAKE/POND', '39000', '']
  137. \endcode
  138. @param map map name
  139. @param layer layer number
  140. @param kwargs v.db.select options
  141. @return dictionary ('columns' and 'values')
  142. """
  143. try:
  144. key = vector_db(map = map)[layer]['key']
  145. except KeyError:
  146. error(_('Missing layer %(layer)d in vector map <%(map)s>') % \
  147. { 'layer' : layer, 'map' : map })
  148. return { 'columns' : [], 'values' : {} }
  149. if kwargs.has_key('columns'):
  150. if key not in kwargs['columns'].split(','):
  151. # add key column if missing
  152. debug("Adding key column to the output")
  153. kwargs['columns'] += ',' + key
  154. ret = read_command('v.db.select',
  155. map = map,
  156. layer = layer,
  157. fs = '|', **kwargs)
  158. if not ret:
  159. error(_('vector_select() failed'))
  160. return { 'columns' : [], 'values' : {} }
  161. columns = []
  162. values = {}
  163. for line in ret.splitlines():
  164. if not columns:
  165. columns = line.split('|')
  166. key_index = columns.index(key)
  167. continue
  168. value = line.split('|')
  169. key_value = int(value[key_index])
  170. values[key_value] = line.split('|')
  171. return { 'columns' : columns,
  172. 'values' : values }
  173. # interface to v.what
  174. def vector_what(map, coord, distance = 0.0):
  175. """!Query vector map at given locations
  176. To query one vector map at one location
  177. @code
  178. print grass.vector_what(map = 'archsites', coord = (595743, 4925281), distance = 250)
  179. [{'Category': 8, 'Map': 'archsites', 'Layer': 1, 'Key_column': 'cat',
  180. 'Database': '/home/martin/grassdata/spearfish60/PERMANENT/dbf/',
  181. 'Mapset': 'PERMANENT', 'Driver': 'dbf',
  182. 'Attributes': {'str1': 'No_Name', 'cat': '8'},
  183. 'Table': 'archsites', 'Type': 'Point', 'Id': 8}]
  184. @endcode
  185. To query one vector map at more locations
  186. @code
  187. for q in grass.vector_what(map = ('archsites', 'roads'), coord = (595743, 4925281),
  188. distance = 250):
  189. print q['Map'], q['Attributes']
  190. archsites {'str1': 'No_Name', 'cat': '8'}
  191. roads {'label': 'interstate', 'cat': '1'}
  192. @endcode
  193. To query more vector maps at one location
  194. @code
  195. for q in grass.vector_what(map = 'archsites', coord = [(595743, 4925281), (597950, 4918898)],
  196. distance = 250):
  197. print q['Map'], q['Attributes']
  198. archsites {'str1': 'No_Name', 'cat': '8'}
  199. archsites {'str1': 'Bob_Miller', 'cat': '22'}
  200. @endcode
  201. @param map vector map(s) to query given as string or list/tuple
  202. @param coord coordinates of query given as tuple (easting, northing) or list of tuples
  203. @param distance query threshold distance (in map units)
  204. @return parsed list
  205. """
  206. if os.environ.has_key("LC_ALL"):
  207. locale = os.environ["LC_ALL"]
  208. os.environ["LC_ALL"] = "C"
  209. if type(map) in (types.StringType, types.UnicodeType):
  210. map_list = [map]
  211. else:
  212. map_list = map
  213. layer_list = ['-1'] * len(map_list)
  214. coord_list = list()
  215. if type(coord) is types.TupleType:
  216. coord_list.append('%f,%f' % (coord[0], coord[1]))
  217. else:
  218. for e, n in coord:
  219. coord_list.append('%f,%f' % (e, n))
  220. ret = read_command('v.what',
  221. quiet = True,
  222. flags = 'ag',
  223. map = ','.join(map_list),
  224. layer = ','.join(layer_list),
  225. east_north = ','.join(coord_list),
  226. distance = float(distance))
  227. if os.environ.has_key("LC_ALL"):
  228. os.environ["LC_ALL"] = locale
  229. data = list()
  230. if not ret:
  231. return data
  232. dict_attrb = None
  233. for item in ret.splitlines():
  234. try:
  235. key, value = __builtin__.map(lambda x: x.strip(), item.split('=', 1))
  236. except ValueError:
  237. continue
  238. if key in ('East', 'North'):
  239. continue
  240. if key == 'Map':
  241. dict_main = { 'Map' : value }
  242. dict_attrb = None
  243. data.append(dict_main)
  244. continue
  245. else:
  246. if dict_attrb is not None:
  247. dict_attrb[key] = value
  248. else:
  249. if key in ('Category', 'Layer', 'Id'):
  250. dict_main[key] = int(value)
  251. else:
  252. dict_main[key] = value
  253. if key == 'Key_column':
  254. # skip attributes
  255. dict_attrb = dict()
  256. dict_main['Attributes'] = dict_attrb
  257. return data