utils.py 16 KB

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