source: grass/trunk/lib/python/pygrass/utils.py

Last change on this file was 73358, checked in by annakrat, 6 years ago

pygrass: work on Python 3 support - fixes to get raster tests working

  • Property svn:eol-style set to native
  • Property svn:mime-type set to text/x-python
File size: 17.6 KB
Line 
1# -*- coding: utf-8 -*-
2import itertools
3import fnmatch
4import os
5from sqlite3 import OperationalError
6
7import grass.lib.gis as libgis
8libgis.G_gisinit('')
9import grass.lib.raster as libraster
10from grass.lib.ctypes_preamble import String
11from grass.script import core as grasscore
12from grass.script import utils as grassutils
13
14from grass.pygrass.errors import GrassError
15
16
17test_vector_name="Utils_test_vector"
18test_raster_name="Utils_test_raster"
19
20def looking(obj, filter_string):
21 """
22 >>> import grass.lib.vector as libvect
23 >>> sorted(looking(libvect, '*by_box*')) # doctest: +NORMALIZE_WHITESPACE
24 ['Vect_select_areas_by_box', 'Vect_select_isles_by_box',
25 'Vect_select_lines_by_box', 'Vect_select_nodes_by_box']
26
27 """
28 word_list = dir(obj)
29 word_list.sort()
30 return fnmatch.filter(word_list, filter_string)
31
32
33def findfiles(dirpath, match=None):
34 """Return a list of the files"""
35 res = []
36 for f in sorted(os.listdir(dirpath)):
37 abspath = os.path.join(dirpath, f)
38 if os.path.isdir(abspath):
39 res.extend(findfiles(abspath, match))
40
41 if match:
42 if fnmatch.fnmatch(abspath, match):
43 res.append(abspath)
44 else:
45 res.append(abspath)
46 return res
47
48
49def findmaps(type, pattern=None, mapset='', location='', gisdbase=''):
50 """Return a list of tuple contining the names of the:
51
52 * map
53 * mapset,
54 * location,
55 * gisdbase
56
57 """
58 from grass.pygrass.gis import Gisdbase, Location, Mapset
59
60 def find_in_location(type, pattern, location):
61 res = []
62 for msetname in location.mapsets():
63 mset = Mapset(msetname, location.name, location.gisdbase)
64 res.extend([(m, mset.name, mset.location, mset.gisdbase)
65 for m in mset.glist(type, pattern)])
66 return res
67
68 def find_in_gisdbase(type, pattern, gisdbase):
69 res = []
70 for loc in gisdbase.locations():
71 res.extend(find_in_location(type, pattern,
72 Location(loc, gisdbase.name)))
73 return res
74
75 if gisdbase and location and mapset:
76 mset = Mapset(mapset, location, gisdbase)
77 return [(m, mset.name, mset.location, mset.gisdbase)
78 for m in mset.glist(type, pattern)]
79 elif gisdbase and location:
80 loc = Location(location, gisdbase)
81 return find_in_location(type, pattern, loc)
82 elif gisdbase:
83 gis = Gisdbase(gisdbase)
84 return find_in_gisdbase(type, pattern, gis)
85 elif location:
86 loc = Location(location)
87 return find_in_location(type, pattern, loc)
88 elif mapset:
89 mset = Mapset(mapset)
90 return [(m, mset.name, mset.location, mset.gisdbase)
91 for m in mset.glist(type, pattern)]
92 else:
93 gis = Gisdbase()
94 return find_in_gisdbase(type, pattern, gis)
95
96
97def remove(oldname, maptype):
98 """Remove a map"""
99 grasscore.run_command('g.remove', quiet=True, flags='f',
100 type=maptype, name=oldname)
101
102
103def rename(oldname, newname, maptype, **kwargs):
104 """Rename a map"""
105 kwargs.update({maptype: '{old},{new}'.format(old=oldname, new=newname), })
106 grasscore.run_command('g.rename', quiet=True, **kwargs)
107
108
109def copy(existingmap, newmap, maptype, **kwargs):
110 """Copy a map
111
112 >>> copy(test_vector_name, 'mycensus', 'vector')
113 >>> rename('mycensus', 'mynewcensus', 'vector')
114 >>> remove('mynewcensus', 'vector')
115
116 """
117 kwargs.update({maptype: '{old},{new}'.format(old=existingmap, new=newmap)})
118 grasscore.run_command('g.copy', quiet=True, **kwargs)
119
120
121def decode(obj, encoding=None):
122 """Decode string coming from c functions,
123 can be ctypes class String, bytes, or None
124 """
125 if isinstance(obj, String):
126 return grassutils.decode(obj.data, encoding=encoding)
127 elif isinstance(obj, bytes):
128 return grassutils.decode(obj)
129 else:
130 # eg None
131 return obj
132
133
134def getenv(env):
135 """Return the current grass environment variables
136
137 >>> from grass.script.core import gisenv
138 >>> getenv("MAPSET") == gisenv()["MAPSET"]
139 True
140
141 """
142 return decode(libgis.G_getenv_nofatal(env))
143
144
145def get_mapset_raster(mapname, mapset=''):
146 """Return the mapset of the raster map
147
148 >>> get_mapset_raster(test_raster_name) == getenv("MAPSET")
149 True
150
151 """
152 return decode(libgis.G_find_raster2(mapname, mapset))
153
154
155def get_mapset_vector(mapname, mapset=''):
156 """Return the mapset of the vector map
157
158 >>> get_mapset_vector(test_vector_name) == getenv("MAPSET")
159 True
160
161 """
162 return decode(libgis.G_find_vector2(mapname, mapset))
163
164
165def is_clean_name(name):
166 """Return if the name is valid
167
168 >>> is_clean_name('census')
169 True
170 >>> is_clean_name('0census')
171 True
172 >>> is_clean_name('census?')
173 True
174 >>> is_clean_name('cénsus')
175 False
176
177 """
178 if libgis.G_legal_filename(name) < 0:
179 return False
180 return True
181
182
183def coor2pixel(coord, region):
184 """Convert coordinates into a pixel row and col
185
186 >>> from grass.pygrass.gis.region import Region
187 >>> reg = Region()
188 >>> coor2pixel((reg.west, reg.north), reg)
189 (0.0, 0.0)
190 >>> coor2pixel((reg.east, reg.south), reg) == (reg.rows, reg.cols)
191 True
192
193 """
194 (east, north) = coord
195 return (libraster.Rast_northing_to_row(north, region.byref()),
196 libraster.Rast_easting_to_col(east, region.byref()))
197
198
199def pixel2coor(pixel, region):
200 """Convert row and col of a pixel into a coordinates
201
202 >>> from grass.pygrass.gis.region import Region
203 >>> reg = Region()
204 >>> pixel2coor((0, 0), reg) == (reg.north, reg.west)
205 True
206 >>> pixel2coor((reg.cols, reg.rows), reg) == (reg.south, reg.east)
207 True
208
209 """
210 (col, row) = pixel
211 return (libraster.Rast_row_to_northing(row, region.byref()),
212 libraster.Rast_col_to_easting(col, region.byref()))
213
214
215def get_raster_for_points(poi_vector, raster, column=None, region=None):
216 """Query a raster map for each point feature of a vector
217
218 Example
219
220 >>> from grass.pygrass.raster import RasterRow
221 >>> from grass.pygrass.gis.region import Region
222 >>> from grass.pygrass.vector import VectorTopo
223 >>> from grass.pygrass.vector.geometry import Point
224
225 Create a vector map
226
227 >>> cols = [(u'cat', 'INTEGER PRIMARY KEY'),
228 ... (u'value', 'double precision')]
229 >>> vect = VectorTopo("test_vect_2")
230 >>> vect.open("w",tab_name="test_vect_2",
231 ... tab_cols=cols)
232 >>> vect.write(Point(10, 6), cat=1, attrs=[10, ])
233 >>> vect.write(Point(12, 6), cat=2, attrs=[12, ])
234 >>> vect.write(Point(14, 6), cat=3, attrs=[14, ])
235 >>> vect.table.conn.commit()
236 >>> vect.close()
237
238 Setup the raster sampling
239
240 >>> region = Region()
241 >>> region.from_rast(test_raster_name)
242 >>> region.set_raster_region()
243 >>> ele = RasterRow(test_raster_name)
244
245 Sample the raster layer at the given points, return a list of values
246
247 >>> l = get_raster_for_points(vect, ele, region=region)
248 >>> l[0] # doctest: +ELLIPSIS
249 (1, 10.0, 6.0, 1)
250 >>> l[1] # doctest: +ELLIPSIS
251 (2, 12.0, 6.0, 1)
252
253 Add a new column and sample again
254
255 >>> vect.open("r")
256 >>> vect.table.columns.add(test_raster_name,'double precision')
257 >>> vect.table.conn.commit()
258 >>> test_raster_name in vect.table.columns
259 True
260 >>> get_raster_for_points(vect, ele, column=test_raster_name, region=region)
261 True
262 >>> vect.table.filters.select('value', test_raster_name)
263 Filters(u'SELECT value, Utils_test_raster FROM test_vect_2;')
264 >>> cur = vect.table.execute()
265 >>> r = cur.fetchall()
266 >>> r[0] # doctest: +ELLIPSIS
267 (10.0, 1.0)
268 >>> r[1] # doctest: +ELLIPSIS
269 (12.0, 1.0)
270 >>> remove('test_vect_2','vect')
271
272 :param poi_vector: A VectorTopo object that contains points
273 :param raster: raster object
274 :param str column: column name to update in the attrinute table,
275 if set to None a list of sampled values will be returned
276 :param region: The region to work with, if not set the current computational region will be used
277
278 :return: True in case of success and a specified column for update,
279 if column name for update was not set a list of (id, x, y, value) is returned
280 """
281 from math import isnan
282 if not column:
283 result = []
284 if region is None:
285 from grass.pygrass.gis.region import Region
286 region = Region()
287 if not poi_vector.is_open():
288 poi_vector.open("r")
289 if not raster.is_open():
290 raster.open("r")
291 if poi_vector.num_primitive_of('point') == 0:
292 raise GrassError(_("Vector doesn't contain points"))
293
294 for poi in poi_vector.viter('points'):
295 val = raster.get_value(poi, region)
296 if column:
297 if val is not None and not isnan(val):
298 poi.attrs[column] = val
299 else:
300 if val is not None and not isnan(val):
301 result.append((poi.id, poi.x, poi.y, val))
302 else:
303 result.append((poi.id, poi.x, poi.y, None))
304 if not column:
305 return result
306 else:
307 poi.attrs.commit()
308 return True
309
310
311def r_export(rast, output='', fmt='png', **kargs):
312 from grass.pygrass.modules import Module
313 if rast.exist():
314 output = output if output else "%s_%s.%s" % (rast.name, rast.mapset,
315 fmt)
316 Module('r.out.%s' % fmt, input=rast.fullname(), output=output,
317 overwrite=True, **kargs)
318 return output
319 else:
320 raise ValueError('Raster map does not exist.')
321
322
323def get_lib_path(modname, libname=None):
324 """Return the path of the libname contained in the module.
325
326 .. deprecated:: 7.1
327 Use :func:`grass.script.utils.get_lib_path` instead.
328 """
329 from grass.script.utils import get_lib_path
330 return get_lib_path(modname=modname, libname=libname)
331
332
333def set_path(modulename, dirname=None, path='.'):
334 """Set sys.path looking in the the local directory GRASS directories.
335
336 :param modulename: string with the name of the GRASS module
337 :param dirname: string with the directory name containing the python
338 libraries, default None
339 :param path: string with the path to reach the dirname locally.
340
341 .. deprecated:: 7.1
342 Use :func:`grass.script.utils.set_path` instead.
343 """
344 from grass.script.utils import set_path
345 return set_path(modulename=modulename, dirname=dirname, path=path)
346
347
348def split_in_chunk(iterable, length=10):
349 """Split a list in chunk.
350
351 >>> for chunk in split_in_chunk(range(25)): print chunk
352 (0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
353 (10, 11, 12, 13, 14, 15, 16, 17, 18, 19)
354 (20, 21, 22, 23, 24)
355 >>> for chunk in split_in_chunk(range(25), 3): print chunk
356 (0, 1, 2)
357 (3, 4, 5)
358 (6, 7, 8)
359 (9, 10, 11)
360 (12, 13, 14)
361 (15, 16, 17)
362 (18, 19, 20)
363 (21, 22, 23)
364 (24,)
365 """
366 it = iter(iterable)
367 while True:
368 chunk = tuple(itertools.islice(it, length))
369 if not chunk:
370 return
371 yield chunk
372
373
374def table_exist(cursor, table_name):
375 """Return True if the table exist False otherwise"""
376 try:
377 # sqlite
378 cursor.execute("SELECT name FROM sqlite_master"
379 " WHERE type='table' AND name='%s';" % table_name)
380 except OperationalError:
381 try:
382 # pg
383 cursor.execute("SELECT EXISTS(SELECT * FROM "
384 "information_schema.tables "
385 "WHERE table_name=%s)" % table_name)
386 except OperationalError:
387 return False
388 one = cursor.fetchone() if cursor else None
389 return True if one and one[0] else False
390
391
392def create_test_vector_map(map_name="test_vector"):
393 """This functions creates a vector map layer with points, lines, boundaries,
394 centroids, areas, isles and attributes for testing purposes
395
396 This should be used in doc and unit tests to create location/mapset
397 independent vector map layer. This map includes 3 points, 3 lines,
398 11 boundaries and 4 centroids. The attribute table contains cat, name
399 and value columns.
400
401 param map_name: The vector map name that should be used
402
403
404
405 P1 P2 P3
406 6 * * *
407 5
408 4 _______ ___ ___ L1 L2 L3
409 Y 3 |A1___ *| *| *| | | |
410 2 | |A2*| | | | | | |
411 1 | |___| |A3 |A4 | | | |
412 0 |_______|___|___| | | |
413 -1
414 -1 0 1 2 3 4 5 6 7 8 9 10 12 14
415 X
416 """
417
418 from grass.pygrass.vector import VectorTopo
419 from grass.pygrass.vector.geometry import Point, Line, Centroid, Boundary
420
421 cols = [(u'cat', 'INTEGER PRIMARY KEY'),
422 (u'name','varchar(50)'),
423 (u'value', 'double precision')]
424 with VectorTopo(map_name, mode='w', tab_name=map_name,
425 tab_cols=cols) as vect:
426
427 # Write 3 points
428 vect.write(Point(10, 6), cat=1, attrs=("point", 1))
429 vect.write(Point(12, 6), cat=1)
430 vect.write(Point(14, 6), cat=1)
431 # Write 3 lines
432 vect.write(Line([(10, 4), (10, 2), (10,0)]), cat=2, attrs=("line", 2))
433 vect.write(Line([(12, 4), (12, 2), (12,0)]), cat=2)
434 vect.write(Line([(14, 4), (14, 2), (14,0)]), cat=2)
435 # boundaries 1 - 4
436 vect.write(Boundary(points=[(0, 0), (0,4)]))
437 vect.write(Boundary(points=[(0, 4), (4,4)]))
438 vect.write(Boundary(points=[(4, 4), (4,0)]))
439 vect.write(Boundary(points=[(4, 0), (0,0)]))
440 # 5. boundary (Isle)
441 vect.write(Boundary(points=[(1, 1), (1,3), (3, 3), (3,1), (1,1)]))
442 # boundaries 6 - 8
443 vect.write(Boundary(points=[(4, 4), (6,4)]))
444 vect.write(Boundary(points=[(6, 4), (6,0)]))
445 vect.write(Boundary(points=[(6, 0), (4,0)]))
446 # boundaries 9 - 11
447 vect.write(Boundary(points=[(6, 4), (8,4)]))
448 vect.write(Boundary(points=[(8, 4), (8,0)]))
449 vect.write(Boundary(points=[(8, 0), (6,0)]))
450 # Centroids, all have the same cat and attribute
451 vect.write(Centroid(x=3.5, y=3.5), cat=3, attrs=("centroid", 3))
452 vect.write(Centroid(x=2.5, y=2.5), cat=3)
453 vect.write(Centroid(x=5.5, y=3.5), cat=3)
454 vect.write(Centroid(x=7.5, y=3.5), cat=3)
455
456 vect.organization = 'Thuenen Institut'
457 vect.person = 'Soeren Gebbert'
458 vect.title = 'Test dataset'
459 vect.comment = 'This is a comment'
460
461 vect.table.conn.commit()
462
463 vect.organization = "Thuenen Institut"
464 vect.person = "Soeren Gebbert"
465 vect.title = "Test dataset"
466 vect.comment = "This is a comment"
467 vect.close()
468
469def create_test_stream_network_map(map_name="streams"):
470 """
471 This functions creates a vector map layer with lines that represent
472 a stream network with two different graphs. The first graph
473 contains a loop, the second can be used as directed graph.
474
475 This should be used in doc and unit tests to create location/mapset
476 independent vector map layer.
477
478 param map_name: The vector map name that should be used
479
480 1(0,2) 3(2,2)
481 \ /
482 1 \ / 2
483 \ /
484 2(1,1)
485 6(0,1) || 5(2,1)
486 5 \ || / 4
487 \||/
488 4(1,0)
489 |
490 | 6
491 |7(1,-1)
492
493 7(0,-1) 8(2,-1)
494 \ /
495 8 \ / 9
496 \ /
497 9(1, -2)
498 |
499 | 10
500 |
501 10(1,-3)
502 """
503
504 from grass.pygrass.vector import VectorTopo
505 from grass.pygrass.vector.geometry import Line
506
507 cols = [(u'cat', 'INTEGER PRIMARY KEY'), (u'id', 'INTEGER')]
508 with VectorTopo(map_name, mode='w', tab_name=map_name,
509 tab_cols=cols) as streams:
510
511 # First flow graph
512 l = Line([(0,2), (0.22, 1.75), (0.55, 1.5), (1,1)])
513 streams.write(l, cat=1, attrs=(1,))
514 l = Line([(2,2),(1,1)])
515 streams.write(l, cat=2, attrs=(2,))
516 l = Line([(1,1), (0.85, 0.5), (1,0)])
517 streams.write(l, cat=3, attrs=(3,))
518 l = Line([(2,1),(1,0)])
519 streams.write(l, cat=4, attrs=(4,))
520 l = Line([(0,1),(1,0)])
521 streams.write(l, cat=5, attrs=(5,))
522 l = Line([(1,0),(1,-1)])
523 streams.write(l, cat=6, attrs=(6,))
524 # Reverse line 3
525 l = Line([(1,0), (1.15, 0.5),(1,1)])
526 streams.write(l, cat=7, attrs=(7,))
527
528 # second flow graph
529 l = Line([(0,-1),(1,-2)])
530 streams.write(l, cat=8, attrs=(8,))
531 l = Line([(2,-1),(1,-2)])
532 streams.write(l, cat=9, attrs=(9,))
533 l = Line([(1,-2),(1,-3)])
534 streams.write(l, cat=10, attrs=(10,))
535
536 streams.organization = 'Thuenen Institut'
537 streams.person = 'Soeren Gebbert'
538 streams.title = 'Test dataset for stream networks'
539 streams.comment = 'This is a comment'
540
541 streams.table.conn.commit()
542 streams.close()
543
544if __name__ == "__main__":
545
546 import doctest
547 from grass.pygrass import utils
548 from grass.script.core import run_command
549
550 utils.create_test_vector_map(test_vector_name)
551 run_command("g.region", n=50, s=0, e=60, w=0, res=1)
552 run_command("r.mapcalc", expression="%s = 1"%(test_raster_name),
553 overwrite=True)
554
555 doctest.testmod()
556
557 """Remove the generated vector map, if exist"""
558 mset = utils.get_mapset_vector(test_vector_name, mapset='')
559 if mset:
560 run_command("g.remove", flags='f', type='vector', name=test_vector_name)
561 mset = utils.get_mapset_raster(test_raster_name, mapset='')
562 if mset:
563 run_command("g.remove", flags='f', type='raster', name=test_raster_name)
Note: See TracBrowser for help on using the repository browser.