GRASS Programmer's Manual  6.5.svn(2014)-r66266
 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 copy
28 import __builtin__
29 
30 from core import *
31 
32 # i18N
33 import gettext
34 gettext.install('grasslibs', os.path.join(os.getenv("GISBASE"), 'locale'), unicode=True)
35 
36 # run "v.db.connect -g ..." and parse output
37 
38 def vector_db(map, **args):
39  """!Return the database connection details for a vector map
40  (interface to `v.db.connect -g'). Example:
41 
42  \code
43  >>> grass.vector_db('lakes')
44  {1: {'layer': '1', 'name': '',
45  'database': '/home/martin/grassdata/nc_spm_08/PERMANENT/dbf/',
46  'driver': 'dbf', 'key': 'cat', 'table': 'lakes'}}
47  \endcode
48 
49  @param map vector map
50  @param args
51 
52  @return dictionary { layer : { 'layer', 'table, 'database', 'driver', 'key' }
53  """
54  s = read_command('v.db.connect', flags = 'g', map = map, fs = ';', **args)
55  result = {}
56 
57  for l in s.splitlines():
58  f = l.split(';')
59  if len(f) != 5:
60  continue
61 
62  if '/' in f[0]:
63  f1 = f[0].split('/')
64  layer = f1[0]
65  name = f1[1]
66  else:
67  layer = f[0]
68  name = ''
69 
70  result[int(layer)] = {
71  'layer' : layer,
72  'name' : name,
73  'table' : f[1],
74  'key' : f[2],
75  'database' : f[3],
76  'driver' : f[4] }
77 
78  return result
79 
80 def vector_layer_db(map, layer):
81  """!Return the database connection details for a vector map layer.
82  If db connection for given layer is not defined, fatal() is called.
83 
84  @param map map name
85  @param layer layer number
86 
87  @return parsed output
88  """
89  try:
90  f = vector_db(map)[int(layer)]
91  except KeyError:
92  fatal(_("Database connection not defined for layer %s") % layer)
93 
94  return f
95 
96 # run "v.info -c ..." and parse output
97 
98 def vector_columns(map, layer = None, getDict = True, **args):
99  """!Return a dictionary (or a list) of the columns for the
100  database table connected to a vector map (interface to `v.info
101  -c').
102 
103  @code
104  >>> vector_columns(urbanarea, getDict = True)
105  {'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'}}
106 
107  >>> vector_columns(urbanarea, getDict = False)
108  ['cat', 'OBJECTID', 'UA', 'NAME', 'UA_TYPE']
109  @endcode
110 
111  @param map map name
112  @param layer layer number or name (None for all layers)
113  @param getDict True to return dictionary of columns otherwise list of column names is returned
114  @param args (v.info's arguments)
115 
116  @return dictionary/list of columns
117  """
118  s = read_command('v.info', flags = 'c', map = map, layer = layer, quiet = True, **args)
119  if getDict:
120  result = dict()
121  else:
122  result = list()
123  i = 0
124  for line in s.splitlines():
125  ctype, cname = line.split('|')
126  if getDict:
127  result[cname] = { 'type' : ctype,
128  'index' : i }
129  else:
130  result.append(cname)
131  i+=1
132 
133  return result
134 
135 # add vector history
136 
137 def vector_history(map):
138  """!Set the command history for a vector map to the command used to
139  invoke the script (interface to `v.support').
140 
141  @param map mapname
142 
143  @return v.support output
144  """
145  run_command('v.support', map = map, cmdhist = os.environ['CMDLINE'])
146 
147 # run "v.info -t" and parse output
148 
150  """!Return information about a vector map (interface to `v.info
151  -t'). Example:
152 
153  \code
154  >>> grass.vector_info_topo('lakes')
155  {'kernels': 0, 'lines': 0, 'centroids': 15279,
156  'boundaries': 27764, 'points': 0, 'faces': 0,
157  'primitives': 43043, 'islands': 7470, 'nodes': 35234, 'map3d': 0, 'areas': 15279}
158  \endcode
159 
160  @param map map name
161 
162  @return parsed output
163  """
164  s = read_command('v.info', flags = 't', map = map)
165  ret = parse_key_val(s, val_type = int)
166  if 'map3d' in ret:
167  ret['map3d'] = bool(ret['map3d'])
168 
169  return ret
170 
171 # interface for v.db.select
172 
173 def vector_db_select(map, layer = 1, **kwargs):
174  """!Get attribute data of selected vector map layer.
175 
176  Function returns list of columns and dictionary of values ordered by
177  key column value. Example:
178 
179  \code
180  >>> print grass.vector_db_select('lakes')['columns']
181  ['cat', 'AREA', 'PERIMETER', 'FULL_HYDRO', 'FULL_HYDR2', 'FTYPE', 'FCODE', 'NAME']
182  >>> print grass.vector_db_select('lakes')['values'][3]
183  ['3', '19512.86146', '708.44683', '4', '55652', 'LAKE/POND', '39000', '']
184  >>> print grass.vector_db_select('lakes', columns = 'FTYPE')['values'][3]
185  ['LAKE/POND']
186  \endcode
187 
188  @param map map name
189  @param layer layer number
190  @param kwargs v.db.select options
191 
192  @return dictionary ('columns' and 'values')
193  """
194  try:
195  key = vector_db(map = map)[layer]['key']
196  except KeyError:
197  error(_('Missing layer %(layer)d in vector map <%(map)s>') % \
198  { 'layer' : layer, 'map' : map })
199  return { 'columns' : [], 'values' : {} }
200 
201  if 'columns' in kwargs:
202  if key not in kwargs['columns'].split(','):
203  # add key column if missing
204  debug("Adding key column to the output")
205  kwargs['columns'] += ',' + key
206 
207  ret = read_command('v.db.select',
208  map = map,
209  layer = layer,
210  **kwargs)
211 
212  if not ret:
213  error(_('vector_db_select() failed'))
214  return { 'columns' : [], 'values' : {} }
215 
216  columns = []
217  values = {}
218  for line in ret.splitlines():
219  if not columns:
220  columns = line.split('|')
221  key_index = columns.index(key)
222  continue
223 
224  value = line.split('|')
225  key_value = int(value[key_index])
226  values[key_value] = line.split('|')
227 
228  return { 'columns' : columns,
229  'values' : values }
230 
231 # interface to v.what
232 def vector_what(map, coord, distance = 0.0):
233  """!Query vector map at given locations
234 
235  To query one vector map at one location
236  @code
237  print grass.vector_what(map = 'archsites', coord = (595743, 4925281), distance = 250)
238 
239  [{'Category': 8, 'Map': 'archsites', 'Layer': 1, 'Key_column': 'cat',
240  'Database': '/home/martin/grassdata/spearfish60/PERMANENT/dbf/',
241  'Mapset': 'PERMANENT', 'Driver': 'dbf',
242  'Attributes': {'str1': 'No_Name', 'cat': '8'},
243  'Table': 'archsites', 'Type': 'Point', 'Id': 8}]
244  @endcode
245 
246  To query one vector map with multiple layers (no additional parameters required)
247  @code
248  for q in grass.vector_what(map = 'some_map', coord = (596532.357143,4920486.21429), distance = 100.0):
249  print q['Map'], q['Layer'], q['Attributes']
250 
251  new_bug_sites 1 {'str1': 'Beetle_site', 'GRASSRGB': '', 'cat': '80'}
252  new_bug_sites 2 {'cat': '80'}
253  @endcode
254 
255  To query more vector maps at one location
256  @code
257  for q in grass.vector_what(map = ('archsites', 'roads'), coord = (595743, 4925281),
258  distance = 250):
259  print q['Map'], q['Attributes']
260 
261  archsites {'str1': 'No_Name', 'cat': '8'}
262  roads {'label': 'interstate', 'cat': '1'}
263  @endcode
264 
265  To query one vector map at more locations
266  @code
267  for q in grass.vector_what(map = 'archsites', coord = [(595743, 4925281), (597950, 4918898)],
268  distance = 250):
269  print q['Map'], q['Attributes']
270 
271  archsites {'str1': 'No_Name', 'cat': '8'}
272  archsites {'str1': 'Bob_Miller', 'cat': '22'}
273  @endcode
274 
275  @param map vector map(s) to query given as string or list/tuple
276  @param coord coordinates of query given as tuple (easting, northing) or list of tuples
277  @param distance query threshold distance (in map units)
278 
279  @return parsed list
280  """
281  if "LC_ALL" in os.environ:
282  locale = os.environ["LC_ALL"]
283  os.environ["LC_ALL"] = "C"
284 
285  if type(map) in (types.StringType, types.UnicodeType):
286  map_list = [map]
287  else:
288  map_list = map
289 
290  coord_list = list()
291  if type(coord) is types.TupleType:
292  coord_list.append('%f,%f' % (coord[0], coord[1]))
293  else:
294  for e, n in coord:
295  coord_list.append('%f,%f' % (e, n))
296 
297  ret = read_command('v.what',
298  quiet = True,
299  flags = 'ag',
300  map = ','.join(map_list),
301  east_north = ','.join(coord_list),
302  distance = float(distance))
303 
304  if "LC_ALL" in os.environ:
305  os.environ["LC_ALL"] = locale
306 
307  data = list()
308  if not ret:
309  return data
310 
311  dict_attrb = None
312  dict_map = None
313  dict_layer = None
314  attr_pseudo_key = 'Attributes'
315  for item in ret.splitlines():
316  try:
317  key, value = __builtin__.map(lambda x: x.strip(), item.split('=', 1))
318  except ValueError:
319  continue
320  if key in ('East', 'North'):
321  continue
322 
323  if key == 'Map':
324  # attach the last one from the previous map
325  if dict_layer is not None:
326  dict_main = copy.copy(dict_map)
327  dict_main.update(dict_layer)
328  data.append(dict_main)
329  dict_map = { key : value }
330  dict_layer = None
331  dict_attrb = None
332  elif key == 'Layer':
333  # attach the last the previous Layer
334  if dict_layer is not None:
335  dict_main = copy.copy(dict_map)
336  dict_main.update(dict_layer)
337  data.append(dict_main)
338  dict_layer = { key: int(value) }
339  dict_attrb = None
340  elif key == 'Key_column':
341  dict_layer[key] = value
342  dict_attrb = dict()
343  dict_layer[attr_pseudo_key] = dict_attrb
344  elif dict_attrb is not None:
345  dict_attrb[key] = value
346  elif dict_layer is not None:
347  if key == 'Category':
348  dict_layer[key] = int(value)
349  else:
350  dict_layer[key] = value
351  else:
352  dict_map[key] = value
353  # TODO: there are some keys which has non-string values
354  # examples: Sq_Meters, Hectares, Acres, Sq_Miles
355 
356  # attach the last one
357  if dict_layer is not None:
358  dict_main = copy.copy(dict_map)
359  dict_main.update(dict_layer)
360  data.append(dict_main)
361 
362  return data
def vector_layer_db
Return the database connection details for a vector map layer.
Definition: vector.py:80
def vector_info_topo
Return information about a vector map (interface to `v.info -t&#39;).
Definition: vector.py:149
def split
Platform spefic shlex.split.
Definition: core/utils.py:37
def fatal
Display an error message using g.message -e, then abort.
Definition: core.py:383
def vector_db_select
Get attribute data of selected vector map layer.
Definition: vector.py:173
def vector_db
Return the database connection details for a vector map (interface to `v.db.connect -g&#39;)...
Definition: vector.py:38
def vector_columns
Return a dictionary (or a list) of the columns for the database table connected to a vector map (inte...
Definition: vector.py:98
Definition: debug.py:1
def parse_key_val
Parse a string into a dictionary, where entries are separated by newlines and the key and value are s...
Definition: core.py:505
def vector_what
Query vector map at given locations.
Definition: vector.py:232
def vector_history
Set the command history for a vector map to the command used to invoke the script (interface to `v...
Definition: vector.py:137
def run_command
Passes all arguments to start_command(), then waits for the process to complete, returning its exit c...
Definition: core.py:179
def read_command
Passes all arguments to pipe_command, then waits for the process to complete, returning its stdout (i...
Definition: core.py:229