array.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425
  1. """
  2. Functions to use GRASS 2D and 3D rasters with NumPy.
  3. Usage:
  4. >>> from __future__ import print_function
  5. >>> import grass.script as gscript
  6. >>> from grass.script import array as garray
  7. >>>
  8. >>> # We create a temporary region that is only valid in this python session
  9. ... gscript.use_temp_region()
  10. >>> gscript.run_command("g.region", n=80, e=120, t=60, s=0, w=0, b=0, res=20, res3=20)
  11. 0
  12. >>>
  13. >>> # Lets create a raster map numpy array
  14. ... # based at the current region settings
  15. ... map2d_1 = garray.array()
  16. >>>
  17. >>> # Write some data
  18. ... for y in range(map2d_1.shape[0]):
  19. ... for x in range(map2d_1.shape[1]):
  20. ... map2d_1[y,x] = y + x
  21. ...
  22. >>> # Lets have a look at the array
  23. ... print(map2d_1)
  24. [[ 0. 1. 2. 3. 4. 5.]
  25. [ 1. 2. 3. 4. 5. 6.]
  26. [ 2. 3. 4. 5. 6. 7.]
  27. [ 3. 4. 5. 6. 7. 8.]]
  28. >>> # This will write the numpy array as GRASS raster map
  29. ... # with name map2d_1
  30. ... map2d_1.write(mapname="map2d_1", overwrite=True)
  31. 0
  32. >>>
  33. >>> # We create a new array from raster map2d_1 to modify it
  34. ... map2d_2 = garray.array(mapname="map2d_1")
  35. >>> # Don't do map2d_2 = map2d_1 % 3
  36. ... # because: this will overwrite the internal temporary filename
  37. ... map2d_2 %= 3
  38. >>> # Show the result
  39. ... print(map2d_2)
  40. [[ 0. 1. 2. 0. 1. 2.]
  41. [ 1. 2. 0. 1. 2. 0.]
  42. [ 2. 0. 1. 2. 0. 1.]
  43. [ 0. 1. 2. 0. 1. 2.]]
  44. >>> # Write the result as new raster map with name map2d_2
  45. ... map2d_2.write(mapname="map2d_2", overwrite=True)
  46. 0
  47. >>>
  48. >>> # Here we create a 3D raster map numpy array
  49. ... # based in the current region settings
  50. ... map3d_1 = garray.array3d()
  51. >>>
  52. >>> # Write some data
  53. ... # Note: the 3D array has map[depth][row][column] order
  54. ... for z in range(map3d_1.shape[0]):
  55. ... for y in range(map3d_1.shape[1]):
  56. ... for x in range(map3d_1.shape[2]):
  57. ... map3d_1[z,y,x] = z + y + x
  58. ...
  59. >>> # Lets have a look at the 3D array
  60. ... print(map3d_1)
  61. [[[ 0. 1. 2. 3. 4. 5.]
  62. [ 1. 2. 3. 4. 5. 6.]
  63. [ 2. 3. 4. 5. 6. 7.]
  64. [ 3. 4. 5. 6. 7. 8.]]
  65. <BLANKLINE>
  66. [[ 1. 2. 3. 4. 5. 6.]
  67. [ 2. 3. 4. 5. 6. 7.]
  68. [ 3. 4. 5. 6. 7. 8.]
  69. [ 4. 5. 6. 7. 8. 9.]]
  70. <BLANKLINE>
  71. [[ 2. 3. 4. 5. 6. 7.]
  72. [ 3. 4. 5. 6. 7. 8.]
  73. [ 4. 5. 6. 7. 8. 9.]
  74. [ 5. 6. 7. 8. 9. 10.]]]
  75. >>> # This will write the numpy array as GRASS 3D raster map
  76. ... # with name map3d_1
  77. ... map3d_1.write(mapname="map3d_1", overwrite=True)
  78. 0
  79. >>> # We create a new 3D array from 3D raster map3d_1 to modify it
  80. ... map3d_2 = garray.array3d(mapname="map3d_1")
  81. >>> # Don't do map3d_2 = map3d_1 % 3
  82. ... # because: this will overwrite the internal temporary filename
  83. ... map3d_2 %= 3
  84. >>> # Show the result
  85. ... print(map3d_2)
  86. [[[ 0. 1. 2. 0. 1. 2.]
  87. [ 1. 2. 0. 1. 2. 0.]
  88. [ 2. 0. 1. 2. 0. 1.]
  89. [ 0. 1. 2. 0. 1. 2.]]
  90. <BLANKLINE>
  91. [[ 1. 2. 0. 1. 2. 0.]
  92. [ 2. 0. 1. 2. 0. 1.]
  93. [ 0. 1. 2. 0. 1. 2.]
  94. [ 1. 2. 0. 1. 2. 0.]]
  95. <BLANKLINE>
  96. [[ 2. 0. 1. 2. 0. 1.]
  97. [ 0. 1. 2. 0. 1. 2.]
  98. [ 1. 2. 0. 1. 2. 0.]
  99. [ 2. 0. 1. 2. 0. 1.]]]
  100. >>> # Write the result as new 3D raster map with name map3d_2
  101. ... map3d_2.write(mapname="map3d_2", overwrite=True)
  102. 0
  103. (C) 2010-2012 by Glynn Clements and the GRASS Development Team
  104. This program is free software under the GNU General Public
  105. License (>=v2). Read the file COPYING that comes with GRASS
  106. for details.
  107. .. sectionauthor:: Glynn Clements
  108. """
  109. from __future__ import absolute_import
  110. import sys
  111. import numpy
  112. from .utils import try_remove
  113. from . import core as gcore
  114. from grass.exceptions import CalledModuleError
  115. ###############################################################################
  116. class _tempfile(object):
  117. def __init__(self):
  118. self.filename = gcore.tempfile()
  119. def __del__(self):
  120. try_remove(self.filename)
  121. ###############################################################################
  122. class array(numpy.memmap):
  123. def __new__(cls, mapname=None, null=None, dtype=numpy.double):
  124. """Define new numpy array
  125. :param cls:
  126. :param dtype: data type (default: numpy.double)
  127. """
  128. reg = gcore.region()
  129. r = reg['rows']
  130. c = reg['cols']
  131. shape = (r, c)
  132. tempfile = _tempfile()
  133. if mapname:
  134. kind = numpy.dtype(dtype).kind
  135. size = numpy.dtype(dtype).itemsize
  136. if kind == 'f':
  137. flags = 'f'
  138. elif kind in 'biu':
  139. flags = 'i'
  140. else:
  141. raise ValueError(_('Invalid kind <%s>') % kind)
  142. if size not in [1, 2, 4, 8]:
  143. raise ValueError(_('Invalid size <%d>') % size)
  144. gcore.run_command(
  145. 'r.out.bin',
  146. flags=flags,
  147. input=mapname,
  148. output=tempfile.filename,
  149. bytes=size,
  150. null=null,
  151. quiet=True,
  152. overwrite=True)
  153. self = numpy.memmap.__new__(
  154. cls,
  155. filename=tempfile.filename,
  156. dtype=dtype,
  157. mode='r+',
  158. shape=shape)
  159. self.tempfile = tempfile
  160. self.filename = tempfile.filename
  161. return self
  162. def read(self, mapname, null=None):
  163. """Read raster map into array
  164. :param str mapname: name of raster map to be read
  165. :param null: null value
  166. :return: 0 on success
  167. :return: non-zero code on failure
  168. .. deprecated:: 7.1
  169. Instead reading the map after creating the array,
  170. pass the map name in the array constructor.
  171. """
  172. if sys.platform == 'win32':
  173. gcore.warning(_("grass.script.array.read is deprecated and does not"
  174. " work on MS Windows, pass raster name in the constructor"))
  175. kind = self.dtype.kind
  176. size = self.dtype.itemsize
  177. if kind == 'f':
  178. flags = 'f'
  179. elif kind in 'biu':
  180. flags = 'i'
  181. else:
  182. raise ValueError(_('Invalid kind <%s>') % kind)
  183. if size not in [1, 2, 4, 8]:
  184. raise ValueError(_('Invalid size <%d>') % size)
  185. try:
  186. gcore.run_command(
  187. 'r.out.bin',
  188. flags=flags,
  189. input=mapname,
  190. output=self.filename,
  191. bytes=size,
  192. null=null,
  193. quiet=True,
  194. overwrite=True)
  195. except CalledModuleError:
  196. return 1
  197. else:
  198. return 0
  199. def write(self, mapname, title=None, null=None, overwrite=None):
  200. """Write array into raster map
  201. :param str mapname: name for raster map
  202. :param str title: title for raster map
  203. :param null: null value
  204. :param bool overwrite: True for overwritting existing raster maps
  205. :return: 0 on success
  206. :return: non-zero code on failure
  207. """
  208. kind = self.dtype.kind
  209. size = self.dtype.itemsize
  210. if kind == 'f':
  211. if size == 4:
  212. flags = 'f'
  213. elif size == 8:
  214. flags = 'd'
  215. else:
  216. raise ValueError(_('Invalid FP size <%d>') % size)
  217. size = None
  218. elif kind in 'biu':
  219. if size not in [1, 2, 4]:
  220. raise ValueError(_('Invalid integer size <%d>') % size)
  221. flags = None
  222. else:
  223. raise ValueError(_('Invalid kind <%s>') % kind)
  224. reg = gcore.region()
  225. try:
  226. gcore.run_command(
  227. 'r.in.bin',
  228. flags=flags,
  229. input=self.filename,
  230. output=mapname,
  231. title=title,
  232. bytes=size,
  233. anull=null,
  234. overwrite=overwrite,
  235. north=reg['n'],
  236. south=reg['s'],
  237. east=reg['e'],
  238. west=reg['w'],
  239. rows=reg['rows'],
  240. cols=reg['cols'])
  241. except CalledModuleError:
  242. return 1
  243. else:
  244. return 0
  245. ###############################################################################
  246. class array3d(numpy.memmap):
  247. def __new__(cls, mapname=None, null=None, dtype=numpy.double):
  248. """Define new 3d numpy array
  249. :param cls:
  250. :param dtype: data type (default: numpy.double)
  251. """
  252. reg = gcore.region(True)
  253. r = reg['rows3']
  254. c = reg['cols3']
  255. d = reg['depths']
  256. shape = (d, r, c)
  257. tempfile = _tempfile()
  258. if mapname:
  259. kind = numpy.dtype(dtype).kind
  260. size = numpy.dtype(dtype).itemsize
  261. if kind == 'f':
  262. flags = None # default is double
  263. elif kind in 'biu':
  264. flags = 'i'
  265. else:
  266. raise ValueError(_('Invalid kind <%s>') % kind)
  267. if size not in [1, 2, 4, 8]:
  268. raise ValueError(_('Invalid size <%d>') % size)
  269. gcore.run_command(
  270. 'r3.out.bin',
  271. flags=flags,
  272. input=mapname,
  273. output=tempfile.filename,
  274. bytes=size,
  275. null=null,
  276. quiet=True,
  277. overwrite=True)
  278. self = numpy.memmap.__new__(
  279. cls,
  280. filename=tempfile.filename,
  281. dtype=dtype,
  282. mode='r+',
  283. shape=shape)
  284. self.tempfile = tempfile
  285. self.filename = tempfile.filename
  286. return self
  287. def read(self, mapname, null=None):
  288. """Read 3D raster map into array
  289. :param str mapname: name of 3D raster map to be read
  290. :param null: null value
  291. :return: 0 on success
  292. :return: non-zero code on failure
  293. .. deprecated:: 7.1
  294. Instead reading the map after creating the array,
  295. pass the map name in the array constructor.
  296. """
  297. if sys.platform == 'win32':
  298. gcore.warning(_("grass.script.array3d.read is deprecated and does not"
  299. " work on MS Windows, pass 3D raster name in the constructor"))
  300. kind = self.dtype.kind
  301. size = self.dtype.itemsize
  302. if kind == 'f':
  303. flags = None # default is double
  304. elif kind in 'biu':
  305. flags = 'i'
  306. else:
  307. raise ValueError(_('Invalid kind <%s>') % kind)
  308. if size not in [1, 2, 4, 8]:
  309. raise ValueError(_('Invalid size <%d>') % size)
  310. try:
  311. gcore.run_command(
  312. 'r3.out.bin',
  313. flags=flags,
  314. input=mapname,
  315. output=self.filename,
  316. bytes=size,
  317. null=null,
  318. quiet=True,
  319. overwrite=True)
  320. except CalledModuleError:
  321. return 1
  322. else:
  323. return 0
  324. def write(self, mapname, null=None, overwrite=None):
  325. """Write array into 3D raster map
  326. :param str mapname: name for 3D raster map
  327. :param null: null value
  328. :param bool overwrite: True for overwriting existing raster maps
  329. :return: 0 on success
  330. :return: non-zero code on failure
  331. """
  332. kind = self.dtype.kind
  333. size = self.dtype.itemsize
  334. flags = None
  335. if kind == 'f':
  336. if size != 4 and size != 8:
  337. raise ValueError(_('Invalid FP size <%d>') % size)
  338. elif kind in 'biu':
  339. if size not in [1, 2, 4, 8]:
  340. raise ValueError(_('Invalid integer size <%d>') % size)
  341. flags = 'i'
  342. else:
  343. raise ValueError(_('Invalid kind <%s>') % kind)
  344. reg = gcore.region(True)
  345. try:
  346. gcore.run_command(
  347. 'r3.in.bin',
  348. flags=flags,
  349. input=self.filename,
  350. output=mapname,
  351. bytes=size,
  352. null=null,
  353. overwrite=overwrite,
  354. north=reg['n'],
  355. south=reg['s'],
  356. top=reg['t'],
  357. bottom=reg['b'],
  358. east=reg['e'],
  359. west=reg['w'],
  360. depths=reg['depths'],
  361. rows=reg['rows3'],
  362. cols=reg['cols3'])
  363. except CalledModuleError:
  364. return 1
  365. else:
  366. return 0