utils.py 17 KB

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