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